package com.xbongbong.pro.statistic.service.result;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.SizeConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasStageEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.StageTypeEnum;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.pojo.StageFindPojo;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.redis.RedisTimeConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.thread.TransmittableThreadLocalUtil;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.detailtab.pojo.DataDetailTabPojo;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.CustomerErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.service.stage.StageFindStrategy;
import com.xbongbong.pro.service.stage.factory.StageFindFactory;
import com.xbongbong.pro.service.toolbox.statistic.help.SystemChartHelp;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.constant.ChartConstant;
import com.xbongbong.pro.statistic.constant.ChartI18Constant;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.IndicatorRuleEnum;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.PanoramaEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.enums.ValueTypeEnum;
import com.xbongbong.pro.statistic.pojo.FiscalYearTimePojo;
import com.xbongbong.pro.statistic.pojo.TimePojo;
import com.xbongbong.pro.statistic.result.pojo.AggsBucketsPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPkPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultRedisPojo;
import com.xbongbong.pro.statistic.result.pojo.CustomerOkFirstSecondPojo;
import com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo;
import com.xbongbong.pro.statistic.result.pojo.FloorAggsKeyPojo;
import com.xbongbong.pro.statistic.result.pojo.PanoramaPojo;
import com.xbongbong.pro.statistic.result.pojo.StageFunnelInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.StageFunnelPojo;
import com.xbongbong.pro.statistic.result.pojo.TitleRightPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultInfoDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultPieInfoDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultCountListVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataSeriesChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataTableVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultTableVO;
import com.xbongbong.pro.statistic.result.pojo.vo.SingleValueVO;
import com.xbongbong.pro.statistic.through.pojo.TableDataInfoNewPojo;
import com.xbongbong.pro.statistic.through.pojo.dto.ThroughDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.ReportTargetEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ChartConfigEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.ContractOutstockEnum;
import com.xbongbong.saas.enums.business.CustomerCommunicateEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.OrderEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryTermEnum;
import com.xbongbong.saas.enums.dictionary.OrderStatusEnum;
import com.xbongbong.saas.enums.subform.ContractProductSubFormEnum;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.CustomerStageLogModel;
import com.xbongbong.saas.model.CustomerStageModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.CardinalityAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 客户相关统计
 * @author zcp
 * @version v1.0
 * @date 2019/2/12 15:48
 * @since v1.0
 */
@Component
public class CrmCustomerResult extends ChartResultParentService implements ChartResultSystem, ChartResultPk, PanoramaResult {
    private static final Logger LOG = LoggerFactory.getLogger(CrmCustomerResult.class);
    @Resource
    private CustomerStageLogModel customerStageLogModel;
    @Resource
    private CustomerStageModel customerStageModel;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private SystemChartHelp systemChartHelp;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private IndexTypeModel indexTypeModel;

    @Override
    public Object getTarget(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            case CUSTOMER_TOTAL_HOME:
                return customerTotalHome(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_TOTAL_CHART:
                return customerTotalAndValid(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_ACTIVE_CHART_MONTH:
            case CUSTOMER_ACTIVE_CHART_DAY:
                return customerActive(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_ACTIVE_HOME_RATE:
                return customerActiveHomeRate(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_ADD_HOME:
            case CUSTOMER_ADD_CHART:
                return customerAdd(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_OK_HOME_COUNT:
                return customerOk(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_OK_HOME_FIRST:
            case CUSTOMER_OK_HOME_SECOND:
                //首页首次、再次成交数
                return customerOkFirstSecond(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_OK_CHART_RATE:
                return customerOkRate(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_INDUSTRY_CHART:
                CustomerManagementEnum industryEnum = CustomerManagementEnum.INDUSTRY;
                String industryName = industryEnum.getAttrName();
                return customerDraw(chartResultPojo, chartResultDetailVO, DictionaryEnum.CUSTOMER_INDUSTRY, industryEnum, industryName, true, false);
            case CUSTOMER_SOURCE_CHART:
                CustomerManagementEnum sourceEnum = CustomerManagementEnum.SOURCE;
                String sourceName = sourceEnum.getAttrName();
                return customerDraw(chartResultPojo, chartResultDetailVO, DictionaryEnum.CUSTOMER_SOURCE, sourceEnum, sourceName, true, false);
            case CUSTOMER_TYPE_CHART:
                CustomerManagementEnum typeEnum = CustomerManagementEnum.TYPE;
                String typeName = typeEnum.getAttrName();
                return customerDraw(chartResultPojo, chartResultDetailVO, DictionaryEnum.CUSTOMER_STATUS, typeEnum, typeName, false, false);
            case CUSTOMER_MAP_CHART:
                boolean mapFlag = true;
                return customerDraw(chartResultPojo, chartResultDetailVO, null, null, "", true, mapFlag);
            case CUSTOMER_TABLE_CHART:
                return customerTable(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_FUNNEL_CHART:
                return customerFunnel(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_LOSE_REASON_CHART:
                // 客户流失原因
                CustomerManagementEnum wastageEnum = CustomerManagementEnum.WASTAGE;
                String wastageName = wastageEnum.getAttrName();
                return customerLoseReason(chartResultPojo, chartResultDetailVO, DictionaryEnum.CUSTOMER_WASTAGE, wastageEnum, wastageName);
            case CUSTOMER_BEFORE_STAGE_CHART:
                // 客户流失前阶段
                return customerBeforeStage(chartResultPojo, chartResultDetailVO, I18nMessageUtil.getMessage(I18nStringConstant.CUSTOMER_LOSE_BEFORE_STAGE));
                //跟进客户相关
            case CUSTOMER_FOLLOW_CHART_MAP:
                return customerFollowMap(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_FOLLOW_OK_CHART_COMPARED:
                return customerFollowOkChartCompared(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_FOLLOW_CHART_RATE:
                return customerFollowRate(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_FOLLOW_HOME:
                return customerFollowHome(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_SALES_ANALYSIS_CHART:
                return salesAnalysis(chartResultPojo, chartResultDetailVO);
            case CUSTOMER_DELIVERY_ANALYSIS_CHART:
                return deliveryAnalysis(chartResultPojo,chartResultDetailVO);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object getValueTarget(ChartResultPojo chartResultPojo) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            case CUSTOMER_TOTAL_BOARD:
                return customerTotalBoard(chartResultPojo);
            case CUSTOMER_ADD_HOME_BOARD:
                return customerAddBoard(chartResultPojo);
            case CUSTOMER_FOLLOW_BOARD:
                return customerFollowBoard(chartResultPojo);
            case CUSTOMER_OK_HOME_COUNT:
                return customerOkBoard(chartResultPojo);
            //客户关怀
            case CUSTOMER_ADD_CUSTOMER_CARE:
                return customerAddCustomerCare(chartResultPojo);
            case CUSTOMER_BIRTHDAY_TOMORROW:
                return tomorrowBirthdayCustomerCare(chartResultPojo);
            //遗忘提醒相关
            case CUSTOMER_FORGET_ONETOTWOWEEKS:
            case CUSTOMER_FORGET_TWOWEEKSTOONEMONTH:
            case CUSTOMER_FORGET_ONETOTWOMONTHS:
            case CUSTOMER_FORGET_MORETHANTWOMONTHS:
                return customerForgetBoard(chartResultPojo);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object getPkTarget(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPkPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            //pk、完成情况（员工排行）
            case PK_CUSTOMER_ADD:
            case PERFORMANCE_CUSTOMER_ADD:
                return pkCustomerAdd(userEntity, chartResultPkPojo, chartResultPkDetailVO);
            case PK_CUSTOMER_FOLLOW:
            case PERFORMANCE_CUSTOMER_FOLLOW:
                return pkCustomerFollow(userEntity, chartResultPkPojo, chartResultPkDetailVO);
            default:
                break;
        }
        return null;
    }

    /**
     * 系统pk范围规则指标公共接口
     *
     * @param userEntity            登录员工
     * @param chartResultPkPojo     pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 15:34
     * @version v1.0
     * @since v1.0
     */
    @Override
    public Object getPkRuleTarget(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPkPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            //pk、完成情况（员工排行）
            case PK_CUSTOMER_ADD:
            case PERFORMANCE_CUSTOMER_ADD:
                return pkRuleCustomerAdd(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO);
            case PK_CUSTOMER_FOLLOW:
            case PERFORMANCE_CUSTOMER_FOLLOW:
                return pkRuleCustomerFollow(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object customer(PanoramaPojo panoramaPojo) throws XbbException {
        PanoramaEnum panoramaEnum = panoramaPojo.getPanoramaEnum();
        switch (panoramaEnum) {
            case CUSTOMER_FORGET:
                return panoramaCustomerForget(panoramaPojo);
            default:
                break;
        }
        return null;
    }

    /**
     * 当前客户总数--该方法只获取客户总数
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/19 20:15
     * @since v1.0
     * @version v1.0
     */
    public Object customerTotalHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //未来时间是否计算 0否 1是，此处默认0不计算
        ElasticAggsPojo elasticAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE, chartResultPojo.getSystemCodeEnum(), 1);
        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 0;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDto, tableFlag, legend, unit, totalFlag, valueTitle);
    }
    /**
     * 图表中心客户总数---包含有效客户数的处理，即一张图上面有两条线
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/20 11:13
     * @since v1.0
     * @version v1.0
     */
    public Object customerTotalAndValid(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //未来时间是否计算 0否 1是，此处默认0不计算
        ElasticAggsPojo totalAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, SystemCodeEnum.CUSTOMER_TOTAL_CHART, 0);
        ElasticAggsPojo validAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, SystemCodeEnum.CUSTOMER_VALID_CHART, 0);

        //右侧展示客户总数
        boolean totalFlag = true;
        String valueTitle = I18nMessageUtil.getMessage(ChartI18Constant.TOTAL_CURRENT_CUSTOMERS);
        String value = String.valueOf(totalAggsPojo.getTotal());

        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = SystemCodeEnum.CUSTOMER_TOTAL_HOME.getName();
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        StatisticResultInfoDTO totalStatisticResultInfoDto = new StatisticResultInfoDTO(throughDto, tableFlag, legend, unit, totalAggsPojo);
        //置入有效客户code（穿透需要指定指标类型）
        ThroughDTO throughDtoValid = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_VALID_CHART);
        legend = I18nMessageUtil.getMessage(ChartI18Constant.ACTIVE_CUSTOMERS);
        StatisticResultInfoDTO validStatisticResultInfoDto = new StatisticResultInfoDTO(throughDtoValid, tableFlag, legend, unit, validAggsPojo);

        List<StatisticResultInfoDTO> statisticResultInfoDtoList = Arrays.asList(totalStatisticResultInfoDto, validStatisticResultInfoDto);
        StatisticResultDTO statisticResultDto = new StatisticResultDTO(totalFlag, value, valueTitle, statisticResultInfoDtoList);
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 当前客户总数（首页看板）
     *
     * @param chartResultPojo
     * @return java.lang.String
     * @throws XbbException 查询总数时抛出异常
     * @author 徐俊杰
     * @date 2019/3/12 14:15
     * @since v1.0
     */
    public String customerTotalBoard(ChartResultPojo chartResultPojo) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_TOTAL_BOARD);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        if (StringUtil.isNotEmpty(redisResult)) {
            return redisResult;
        }
        //未来时间是否计算 0否 1是，此处默认0不计算
        String fieldTime = "addTime";
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Team(chartResultPojo, fieldTime, false);
        // chartRuleQueryHelp.formOpenBase(boolQueryBuilder, chartResultPojo, XbbRefTypeEnum.CUSTOMER_MANAGEMENT);
        /*--------再获取出截至到startTime的所有客户数--------*/
        IndexTypeEnum indexTypeEnum = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        int count = systemChartHelp.getCount4Total(indexTypeEnum, boolQueryBuilder);
        redisResult = String.valueOf(count);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisResult, RedisTimeConstant.TINY_DURATION);
        return redisResult;
    }

    /**
     * 销售当前时间段的总人数（有客户的人）
     *
     * @param chartResultPojo
     * @return com.xbongbong.pro.statistic.pojo.vo.ResultCountListVO
     * @author 徐俊杰
     * @date 2019/2/25 8:37
     * @since v1.0
     */
    public ResultCountListVO customerTotalUserId(ChartResultPojo chartResultPojo) throws XbbException {
        String fieldTime = "addTime";
        /*--------处理查询条件：第一次查询，先得到时间段内的数据，把区间内的时间分桶--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Team(chartResultPojo, fieldTime, true);
        //表本身的createId不能变更，因此在data字典内增加创建人key
        String fieldGroup = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.CREATOR);
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        FloorAggsKeyPojo zoneFloorAggsKeyPojo = systemChartHelp.getFloorAggsKey(chartResultPojo, customerIndex,
                boolQueryBuilder, fieldTime, fieldGroup, true);
        //将参数根据ResultCountListVO封装
        Map<String, Set> map = zoneFloorAggsKeyPojo.getResultMap();
        /*--------再获取出截至到startTime的所有客户数--------*/
        //移除addTime，重新塞入新的条件
        esHelper.removeSearchCondition(boolQueryBuilder, fieldTime);
        int startTime = chartResultPojo.getStartTime();
        boolQueryBuilder.filter(rangeQuery(fieldTime).lt(startTime));
        FloorAggsKeyPojo pastTotalFloorAggsKeyPojo = systemChartHelp.getFloorAggsKey(chartResultPojo, customerIndex,
                boolQueryBuilder, fieldTime, fieldGroup, true);
        Set pastTotalSet = pastTotalFloorAggsKeyPojo.getTotalSet();
        if (Objects.isNull(pastTotalSet)) {
            pastTotalSet = new HashSet();
        }
        /*--------最后得到总的创建人数--------*/
        List<Integer> resultList = new ArrayList<>();
        for (Entry entry : map.entrySet()) {
            Set entryValue = (Set)entry.getValue();
            pastTotalSet.addAll(entryValue);
            Integer result = pastTotalSet.size();
            resultList.add(result);
        }
        Integer total = pastTotalSet.size();
        return new ResultCountListVO(total, resultList);
    }
    /**
     * 图表中心活跃度分析，包含活跃个数、活跃比例
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/20 17:10
     * @since v1.0
     * @version v1.0
     */
    public Object customerActive(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo activeAggsPojo = customerActive2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        //未来时间是否计算 0否 1是，此处默认1计算
        ElasticAggsPojo totalAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, SystemCodeEnum.CUSTOMER_TOTAL_CHART, 1);
        List<AggsBucketsPojo> activeList = activeAggsPojo.getBuckets();
        List<AggsBucketsPojo> totalList = totalAggsPojo.getBuckets();

        ElasticAggsPojo rateAggsPojo = new ElasticAggsPojo();
        List<AggsBucketsPojo> rateList = rateAggsPojo.getBuckets();
        for (int j = 0; j < activeList.size(); j++) {
            AggsBucketsPojo activePojo = activeList.get(j);
            AggsBucketsPojo totalPojo = totalList.get(j);
            String countStr = activePojo.getValue();
            String totalStr = totalPojo.getValue();
            Integer count = StringUtil.toInt(countStr, 0);
            Integer total = StringUtil.toInt(totalStr, 0);
            //乘以100，前端显示直接拼“%”即可
            Double activeRate = (total == 0)? 0 : Arith.div(count, total) * 100;
            if (activeRate > 0) {
                activeRate = Arith.div(activeRate, 1, 2);
            }
            AggsBucketsPojo ratePojo = new AggsBucketsPojo(activePojo.getKey(), activeRate + "%");
            rateList.add(ratePojo);
        }
        rateAggsPojo.setBuckets(rateList);

        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        //分别采用两个不同单位的y轴，默认为yAxisIndex: 0，当为1时，代表另外一个y坐标轴
        Integer yAxisIndex = 0;
        Integer hide = 0;
        String legend = I18nMessageUtil.getMessage(I18nStringConstant.ACTIVE_NUMBER);
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = false;
        StatisticResultInfoDTO activeStatisticResultInfoDto = new StatisticResultInfoDTO(throughDto, tableFlag, yAxisIndex, hide, legend, unit, activeAggsPojo);
        yAxisIndex = 1;
        legend = I18nMessageUtil.getMessage(ChartI18Constant.CUSTOMER_ACTIVE_RATIO);
        unit = systemChartHelp.getUnit("%");;
        StatisticResultInfoDTO rateStatisticResultInfoDto = new StatisticResultInfoDTO(throughDto, tableFlag, yAxisIndex, hide, legend, unit, rateAggsPojo);
        List<StatisticResultInfoDTO> statisticResultInfoDtoList = Arrays.asList(activeStatisticResultInfoDto, rateStatisticResultInfoDto);
        StatisticResultDTO statisticResultDto = new StatisticResultDTO(totalFlag, "", null, statisticResultInfoDtoList);
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 客户活跃率（首页）
     *
     * @param chartResultPojo corpid, refId, time
     * @param chartResultDetailVO 结果VO
     * @return java.lang.Object
     * @throws XbbException 查询活跃客户数和总客户数时抛出异常
     * @author 徐俊杰
     * @date 2019/3/15 10:48
     * @since v1.0
     */
    public Object customerActiveHomeRate(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo activeRateAggsPojo = new ElasticAggsPojo();
        ElasticAggsPojo activeAggsPojo = customerActive2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE);
        //未来时间是否计算 0否 1是，此处默认1计算
        ElasticAggsPojo totalAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE, SystemCodeEnum.CUSTOMER_TOTAL_CHART, 1);
        Integer active = StringUtil.toInt(activeAggsPojo.getTotal(), 0);
        Integer total = StringUtil.toInt(totalAggsPojo.getTotal(), 0);
        Double activeRate = (total == 0)? 0 : Arith.div(active, total) * 100;
        if (activeRate > 0) {
            activeRate = Arith.div(activeRate, 1, 2);
        }
        activeRateAggsPojo.setTotal(activeRate.toString() + "%");
        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 0;
        String legend = null;
        String unit = null;
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(activeRateAggsPojo, chartResultPojo, chartResultDetailVO, throughDto, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 新增客户
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/14 17:03
     * @since v1.0
     * @version v1.0
     */
    public Object customerAdd(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = customerAdd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = IndicatorRuleEnum.CUSTOMER_ADD.getName();
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = IndicatorRuleEnum.CUSTOMER_ADD.getName();
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDto, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 新增客户数（首页看板）
     *
     * @param chartResultPojo
     * @return java.lang.String
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/3/12 16:31
     * @since v1.0
     */
    public String customerAddBoard(ChartResultPojo chartResultPojo) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_ADD_HOME_BOARD);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);

        if (!chartResultPojo.isReadCache()) {
            redisResult = null;
        }

        if (StringUtil.isNotEmpty(redisResult)) {
            return redisResult;
        }
        /*--------处理查询条件--------*/
        String fieldTime = "addTime";
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Create(true, chartResultPojo, fieldTime);
        // chartRuleQueryHelp.formOpenBase(boolQueryBuilder, chartResultPojo, XbbRefTypeEnum.CUSTOMER_MANAGEMENT);
        IndexTypeEnum customerIndex = indexTypeModel.getIndexType(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(customerIndex, boolQueryBuilder, null);
        redisResult = elasticAggsPojo.getTotal();
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisResult, RedisTimeConstant.TINY_DURATION);
        return redisResult;
    }

    /**
     * 客户关怀，七天内新增客户
     *
     * @param chartResultPojo
     * @return java.lang.String
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/2/26 15:47
     * @since v1.0
     */
    public String customerAddCustomerCare(ChartResultPojo chartResultPojo) throws XbbException {
        //时间范围
        Integer endTime = DateUtil.getInt();
        // 减七天时间
        Integer startTime = endTime - TimeConstant.SECONDS_PER_WEEK;
        chartResultPojo.setStartTime(startTime);
        chartResultPojo.setEndTime(endTime);
        return customerAddBoard(chartResultPojo);
    }
    /**
     * 客户关怀，明日生日客户
     *
     * @param chartResultPojo 入参
     * @return java.lang.String
     * @author 徐俊杰
     * @date 2019/6/15 11:16
     * @since v1.0
     */
    private String tomorrowBirthdayCustomerCare(ChartResultPojo chartResultPojo) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_BIRTHDAY_TOMORROW);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        if (StringUtil.isNotEmpty(redisResult)) {
            return redisResult;
        }
        Integer startTime = DateUtil.getTodayInt();
        Integer endTime = startTime + TimeConstant.SECONDS_TWO_DAY;
        BoolQueryBuilder birthdayQuery = chartQueryHelp.customerQuery4Birthday(chartResultPojo, startTime, endTime);
        IndexTypeEnum customerIndex = indexTypeModel.getIndexType(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(customerIndex, birthdayQuery, null);
        redisResult = elasticAggsPojo.getTotal();
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisResult, RedisTimeConstant.TINY_DURATION);
        return redisResult;
    }
    /**
     * 成交客户
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/22 22:12
     * @since v1.0
     * @version v1.0
     */
    public Object customerOk(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = SystemCodeEnum.CUSTOMER_OK_HOME_COUNT;
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, systemCodeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);

        if (!chartResultPojo.isReadCache()) {
            redisResult = null;
        }

        ChartResultDetailVO redisChartResultDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultDetailVO.class);
        if (Objects.nonNull(redisChartResultDetailVO)) {
            return redisChartResultDetailVO;
        }
        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerOkQuery(chartResultPojo, true);
        //时间聚合字段
        String fieldTime = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_TIME);
        //排重字段
        String fieldGroup = ContractEnum.getEsAttr4Keyword(ContractEnum.LINK_CUSTOMER);

        //用关联客户id聚合结果
        ElasticAggsPojo elasticAggsPojo = systemChartHelp.distinctAggregations(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, fieldTime, fieldGroup);
        ElasticAggsPojo elasticAggsPojoTotal = systemChartHelp.distinctAggregations(chartResultPojo, ValueTypeEnum.VALUE_TYPE, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, fieldTime, fieldGroup);
        elasticAggsPojo.setTotal(elasticAggsPojoTotal.getTotal());
        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = systemCodeEnum.getName();
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = "成交客户数";
        redisChartResultDetailVO = systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDto, tableFlag, legend, unit, totalFlag, valueTitle);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisChartResultDetailVO, RedisTimeConstant.TINY_DURATION);
        return redisChartResultDetailVO;
    }

    /**
     * 成交客户总数
     * @param chartResultPojo
     * @return java.lang.String
     * @throws XbbException
     * @author zcp
     * @date 2019/4/15 20:56
     * @since v1.0
     * @version v1.0
     */
    public String customerOkBoard(ChartResultPojo chartResultPojo) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_OK_HOME_COUNT);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        if (StringUtil.isNotEmpty(redisResult)) {
            return redisResult;
        }
        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerOkQuery(chartResultPojo, true);
        //时间聚合字段
        String fieldTime = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_TIME);
        //排重字段
        String fieldGroup = ContractEnum.getEsAttr4Keyword(ContractEnum.LINK_CUSTOMER);
        //用关联客户id聚合结果
        ElasticAggsPojo elasticAggsPojoTotal = systemChartHelp.distinctAggregations(chartResultPojo, ValueTypeEnum.VALUE_TYPE, IndexTypeEnum.IDX_SAAS_CONTRACT, boolQueryBuilder, fieldTime, fieldGroup);
        redisResult = elasticAggsPojoTotal.getTotal();
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisResult, RedisTimeConstant.TINY_DURATION);
        return redisResult;
    }

    /**
     * 客户首次成交、再次成交（复购客户）
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/23 14:12
     * @since v1.0
     * @version v1.0
     */
    public Object customerOkFirstSecond(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        CustomerOkFirstSecondPojo customerOkFirstSecondPojo = customerOkFirstSecondRefactor(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        String value = "";
        JSONArray valueArray = new JSONArray();
        if (systemCodeEnum == SystemCodeEnum.CUSTOMER_OK_HOME_FIRST) {
            //首次成交客户数
            value = String.valueOf(customerOkFirstSecondPojo.getFirstTotal());
            valueArray = JSONArray.parseArray(JSON.toJSONString(customerOkFirstSecondPojo.getFirstResultList()));
        } else if (systemCodeEnum == SystemCodeEnum.CUSTOMER_OK_HOME_SECOND) {
            //复购客户数
            value = String.valueOf(customerOkFirstSecondPojo.getSecondTotal());
            valueArray = JSONArray.parseArray(JSON.toJSONString(customerOkFirstSecondPojo.getSecondResultList()));
        }
        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPojo.getFiscalYearTimePojo(), chartResultPojo.getStartTime(), chartResultPojo.getEndTime());
        String through = throughHelp.getThrough(throughDto, timePojo);
        ResultChartVO resultChartVo = new ResultChartVO();
        resultChartVo.setTotalFlag(true);
        resultChartVo.setValue(value);
        resultChartVo.setThrough(through);
        chartResultDetailVO = systemChartHelp.packageResult4Chart(chartResultPojo, chartResultDetailVO, resultChartVo, valueArray);
        return chartResultDetailVO;
    }
    /**
     * 获取图表中心客户转化率分析，结构：一张图（包含三条线），一张表（除表头三行数据）
     * 三个数据分别为：首次成交率，再次成交率，流失率
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/23 20:51
     * @since v1.0
     * @version v1.0
     */
    public Object customerOkRate(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //首次、再次成交客户相关结果
        CustomerOkFirstSecondPojo customerOkFirstSecondPojo = customerOkFirstSecondRefactor(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        //流失客户
        ResultCountListVO customerLoseVO = customerLose2ResultCountListVO(chartResultPojo);
        //客户总数vo
        //未来时间是否计算 0否 1是，默认1计算;
        int futureCalc = 1;
        ResultCountListVO customerTotalVO = customerTotal2ResultCountListVO(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, SystemCodeEnum.CUSTOMER_TOTAL_CHART, futureCalc);

        //首次成交list
        List<Integer> countListFirstList = customerOkFirstSecondPojo.getFirstResultList();
        //再次成交list
        List<Integer> countListSecondList = customerOkFirstSecondPojo.getSecondResultList();
        //流失list
        List<Integer> loseList = customerLoseVO.getResultList();
        //客户总数list
        List<Integer> totalCustomerCountList = customerTotalVO.getResultList();

        //计算并封装：首次成交率，再次成交率，流失率
        ElasticAggsPojo elasticAggsPojo4FirstRate = new ElasticAggsPojo();
        ElasticAggsPojo elasticAggsPojo4SecondRate = new ElasticAggsPojo();
        ElasticAggsPojo elasticAggsPojo4LoseRate = new ElasticAggsPojo();
        List<AggsBucketsPojo> aggsBucketsPojos4FirstRate = new ArrayList<>();
        List<AggsBucketsPojo> aggsBucketsPojos4SecondRate = new ArrayList<>();
        List<AggsBucketsPojo> aggsBucketsPojos4LoseRate = new ArrayList<>();
        for (int i = 0; i < totalCustomerCountList.size(); i++) {
            Integer totalCount = totalCustomerCountList.get(i);
            int totalCustomerCount = totalCount == null ? 0 : totalCount;
            //首次成交率
            Double firstRate = ChartResultUtil.getRate(countListFirstList.get(i), totalCustomerCount);
            AggsBucketsPojo firstPojo = new AggsBucketsPojo("", firstRate + "%");
            aggsBucketsPojos4FirstRate.add(firstPojo);
            //再次成交率
            Double secondRate = ChartResultUtil.getRate(countListSecondList.get(i), totalCustomerCount);
            AggsBucketsPojo secondPojo = new AggsBucketsPojo("", secondRate + "%");
            aggsBucketsPojos4SecondRate.add(secondPojo);
            //流失率
            Integer lose = loseList.get(i);
            Double loseRate = ChartResultUtil.getRate(lose, totalCustomerCount);
            AggsBucketsPojo losePojo = new AggsBucketsPojo("", loseRate + "%");
            aggsBucketsPojos4LoseRate.add(losePojo);
        }
        elasticAggsPojo4FirstRate.setBuckets(aggsBucketsPojos4FirstRate);
        elasticAggsPojo4SecondRate.setBuckets(aggsBucketsPojos4SecondRate);
        elasticAggsPojo4LoseRate.setBuckets(aggsBucketsPojos4LoseRate);

        ThroughDTO throughDtoFirst = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_OK_HOME_FIRST);
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = I18nMessageUtil.getMessage(I18nStringConstant.FIRST_TRANSACTION_RATE);
        String unit = systemChartHelp.getUnit("%");
        Boolean totalFlag = false;
        StatisticResultInfoDTO firstStatisticResultInfoDto = new StatisticResultInfoDTO(throughDtoFirst, tableFlag, 0, 0, legend, unit, elasticAggsPojo4FirstRate);
        //置入再次成交code（穿透需要指定指标类型）
        ThroughDTO throughDtoSecond = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_OK_HOME_SECOND);
        legend = I18nMessageUtil.getMessage(ChartI18Constant.CUSTOMER_RE_SOLD_RATE);
        StatisticResultInfoDTO secondStatisticResultInfoDto = new StatisticResultInfoDTO(throughDtoSecond, tableFlag, 0, 0, legend, unit, elasticAggsPojo4SecondRate);
        //置入流失code（穿透需要指定指标类型）
        ThroughDTO throughDtoLose = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_LOSE);
        legend = I18nMessageUtil.getMessage(ChartI18Constant.CUSTOMER_RECHURN_RATE);
        StatisticResultInfoDTO loseStatisticResultInfoDto = new StatisticResultInfoDTO(throughDtoLose, tableFlag, 0, 0, legend, unit, elasticAggsPojo4LoseRate);
        List<StatisticResultInfoDTO> statisticResultInfoDtoList = Arrays.asList(firstStatisticResultInfoDto, secondStatisticResultInfoDto, loseStatisticResultInfoDto);
        StatisticResultDTO statisticResultDto = new StatisticResultDTO(totalFlag, "", null, statisticResultInfoDtoList);
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }
    /**
     * 客户画像：行业、来源、状态、地图
     * @param chartResultPojo 请求系统指标接口需要用到的pojo类（内部存系统指标统计时需要的参数）
     * @param chartResultDetailVO 统计需要渲染的图（表---可能同时存在，可能某一个存在）塞入该vo
     * @param dictionaryEnum 数据字典枚举，地图无需传该值
     * @param attrEnum 客户字段枚举，地图无需传该值
     * @param tableName 表格第一行第一列名称：客户行业、客户来源、客户状态
     * @param flag true需要处理成交客户，false不需要处理成交客户（如客户状态就不需要处理成交客户）
     * @param mapFlag true地图，fals非地图
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/24 21:38
     * @since v1.0
     * @version v1.0
     */
    public Object customerDraw(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO, DictionaryEnum dictionaryEnum, CustomerManagementEnum attrEnum, String tableName, boolean flag, boolean mapFlag) throws XbbException {
        //所有客户
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        ThroughDTO allThroughDTO = new ThroughDTO(chartResultPojo, systemCodeEnum);
        List<ResultDataSeriesChartVO> list = customerDraw(chartResultPojo, dictionaryEnum, attrEnum, false, mapFlag);
        List<StatisticResultPieInfoDTO> pieInfoDtoList;
        if (flag) {
            //成交客户
            List<ResultDataSeriesChartVO> okList = customerDraw(chartResultPojo, dictionaryEnum, attrEnum, true, mapFlag);
            formatUnknow(list, okList);

            SystemCodeEnum okSystemCodeEnum = SystemCodeEnum.getCustomerDrawOkByAll(systemCodeEnum);
            StatisticResultPieInfoDTO allStatisticResultPieInfoDto = new StatisticResultPieInfoDTO(I18nMessageUtil.getMessage(ChartI18Constant.ALL_CUSTOMERS), list, allThroughDTO);
            ThroughDTO okThroughDTO = new ThroughDTO(chartResultPojo, okSystemCodeEnum);
            StatisticResultPieInfoDTO okStatisticResultPieInfoDto = new StatisticResultPieInfoDTO(I18nMessageUtil.getMessage(ChartI18Constant.DEAL_CUSTOMERS), okList, okThroughDTO);
            pieInfoDtoList = Arrays.asList(allStatisticResultPieInfoDto, okStatisticResultPieInfoDto);
        }else {
            StatisticResultPieInfoDTO allStatisticResultPieInfoDto = new StatisticResultPieInfoDTO(I18nMessageUtil.getMessage(ChartI18Constant.ALL_CUSTOMERS), list, allThroughDTO);
            pieInfoDtoList = Collections.singletonList(allStatisticResultPieInfoDto);
        }
        if (mapFlag) {
            return systemChartHelp.packageResult4Map(I18nMessageUtil.getMessage(ChartI18Constant.NUMBER_CUSTOMERS), pieInfoDtoList, chartResultPojo, chartResultDetailVO);
        } else {
            return systemChartHelp.packageResult4Pie(tableName, pieInfoDtoList, chartResultPojo, chartResultDetailVO);
        }
    }

    /**
     * 客户汇总报表
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/24 15:08
     * @since v1.0
     * @version v1.0
     */
    public Object customerTable(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //未来时间是否计算 0否 1是，默认0不计算;
        ElasticAggsPojo totalAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, SystemCodeEnum.CUSTOMER_TOTAL_CHART, 0);
        ElasticAggsPojo validAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, SystemCodeEnum.CUSTOMER_VALID_CHART, 0);
        ElasticAggsPojo addAggsPojo = customerAdd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        CustomerOkFirstSecondPojo customerOkFirstSecondPojo = customerOkFirstSecondRefactor(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);

        //-----设置返回的resultTableVO的各个数据
        ResultTableVO resultTableVO = new ResultTableVO();
        //（1）设置headMemo
        String headMemo = String.format(I18nMessageUtil.getMessage(ChartI18Constant.CUSTOMER_MESSAGE_SUMMARY),totalAggsPojo.getTotal(),validAggsPojo.getTotal(),addAggsPojo.getTotal(),customerOkFirstSecondPojo.getFirstTotal(),customerOkFirstSecondPojo.getSecondTotal());
        resultTableVO.setHeadMemo(headMemo);
        //（2）设置title
        List<String> title = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.CUSTOMER_SUMMARY_TITLE).split(","));
        resultTableVO.setTitle(systemChartHelp.titleNumRight(title));
        //（3）设置data
        List<List<ResultDataTableVO>> resultDataTableVOList = new ArrayList<>();
        //每行的数据
        List<String> dateTitleList = new ArrayList<>(chartResultPojo.getDateTitleList());
        List<AggsBucketsPojo> totalBuckets = totalAggsPojo.getBuckets();
        List<AggsBucketsPojo> validBuckets = validAggsPojo.getBuckets();
        List<AggsBucketsPojo> addBuckets = addAggsPojo.getBuckets();
        List<Integer> countListFirstList = customerOkFirstSecondPojo.getFirstResultList();
        List<Integer> countListSecondList = customerOkFirstSecondPojo.getSecondResultList();
        //处理穿透
        List<Integer> startTimeList = chartResultPojo.getStartTimeList();
        List<Integer> endTimeList = chartResultPojo.getEndTimeList();
        FiscalYearTimePojo fiscalYearTimePojo = chartResultPojo.getFiscalYearTimePojo();
        boolean splitFlag = true;
        //处理每行数据
        for (int i = 0; i < dateTitleList.size(); i++) {
            TimePojo timePojo = throughHelp.formatThroughTimeInfo(splitFlag, fiscalYearTimePojo, startTimeList.get(i), endTimeList.get(i));
            String time = dateTitleList.get(i);
            String totalCount = totalBuckets.get(i).getValue();
            String validCount = validBuckets.get(i).getValue();
            String addCount = addBuckets.get(i).getValue();
            String firstCount = countListFirstList == null ? "0" : countListFirstList.get(i) + "";
            String secondCount = countListSecondList == null ? "0" : countListSecondList.get(i) + "";

            //表数据，是一个值一个对象
            ResultDataTableVO timeVO = new ResultDataTableVO(time, null);
            ThroughDTO throughDto = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_TOTAL_CHART);
            ResultDataTableVO totalCountVO = throughHelp.formatResultDataTableVO(totalCount, throughDto, timePojo);
            ThroughDTO throughDtoValid = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_VALID_CHART);
            ResultDataTableVO validCountVO = throughHelp.formatResultDataTableVO(validCount, throughDtoValid, timePojo);
            ThroughDTO throughDtoAdd = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_ADD_CHART);
            ResultDataTableVO addCountVO = throughHelp.formatResultDataTableVO(addCount, throughDtoAdd, timePojo);
            ThroughDTO throughDtoFirst = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_OK_HOME_FIRST);
            ResultDataTableVO firstCountVO = throughHelp.formatResultDataTableVO(firstCount, throughDtoFirst, timePojo);
            ThroughDTO throughDtoSecond = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_OK_HOME_SECOND);
            ResultDataTableVO secondCountVO = throughHelp.formatResultDataTableVO(secondCount, throughDtoSecond, timePojo);
            List<ResultDataTableVO> resultDataTableVOs = Arrays.asList(timeVO, totalCountVO, validCountVO, addCountVO, firstCountVO, secondCountVO);
            resultDataTableVOList.add(resultDataTableVOs);
        }
        resultTableVO.setData(resultDataTableVOList);
        resultTableVO.setTableName("客户汇总表");
        //-----表相关塞入最终结果chartResultDetailVO内
        chartResultDetailVO.setTable(resultTableVO);
        return chartResultDetailVO;
    }

    /**
     * 客户阶段漏斗--按照客户新建时间统计
     * 客户阶段转化率（排除成交及成交之后阶段，只包含普通阶段）：该阶段后面所有阶段客户总数除以 从当前阶段开始的所有客户数 作为该阶段的转化率。
     * 比如，假设总共有5个阶段，阶段1的转化率=阶段(2+3+4+5)数/5个阶段总数；阶段2的转化率=(3+4+5)数/5个阶段总数，以此类推
     * 客户阶段平均停留时长（不计算流失和成交及之后所有阶段，只计算普通阶段）
     * 分两种情况：
     * （1）客户还处于该阶段，则按照截至到nowTime（当前时间）减去进入该阶段的时间，差值即停留时长；
     * （2）客户已经改到下面的阶段，则直接按照离开阶段的时间减去进入到该阶段时的时间，差值即停留时长。
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/3/11 19:31
     * @since v1.0
     * @version v1.0
     */
    public Object customerFunnel(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = SystemCodeEnum.CUSTOMER_FUNNEL_CHART;
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, systemCodeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ChartResultDetailVO redisChartResultDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultDetailVO.class);
        if (Objects.nonNull(redisChartResultDetailVO)) {
            return redisChartResultDetailVO;
        }
        Long formId = chartResultPojo.getRefId();
        if (formId == null || formId == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, String.format(StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(CommonConstant.FORM)));
        }
        //阶段id--该阶段对应的机会数、预计金额Object
        StageFunnelPojo stageFunnelPojo = getFunnel4Customer(chartResultPojo);
        //阶段code--平均停留时长
        Map<String, Double> dayMap = getAverageStayTime(chartResultPojo, stageFunnelPojo.getCalcStayStageCodeIn());

        redisChartResultDetailVO = packageFunnelFull(chartResultPojo, chartResultDetailVO, stageFunnelPojo.getSaleStageList(), stageFunnelPojo, dayMap);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisChartResultDetailVO, RedisTimeConstant.TINY_DURATION);
        return redisChartResultDetailVO;
    }

    /**
     * 客户分析--客户流失分析--流失原因分析
     * @param chartResultPojo 请求系统指标接口需要用到的pojo类（内部存系统指标统计时需要的参数）
     * @param chartResultDetailVO 统计需要渲染的图（表---可能同时存在，可能某一个存在）塞入该vo
     * @param dictionaryEnum 数据字典枚举，地图无需传该值
     * @param attrEnum 客户字段枚举，地图无需传该值
     * @param tableName 表格第一行第一列名称：客户行业、客户来源、客户状态
     * @return java.lang.Object
     * @throws XbbException
     * @author youli.chen
     * @date 2019/2/24 21:38
     * @since v1.0
     * @version v1.0
     */
    public Object customerLoseReason(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO, DictionaryEnum dictionaryEnum, CustomerManagementEnum attrEnum, String tableName) throws XbbException {
        //所有客户
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        ThroughDTO allThroughDTO = new ThroughDTO(chartResultPojo, systemCodeEnum);
        List<ResultDataSeriesChartVO> list = customerLose(chartResultPojo, dictionaryEnum, attrEnum);

        StatisticResultPieInfoDTO allStatisticResultPieInfoDto = new StatisticResultPieInfoDTO("流失原因", list, allThroughDTO);
        List<StatisticResultPieInfoDTO> pieInfoDtoList = Collections.singletonList(allStatisticResultPieInfoDto);

        return systemChartHelp.packageResult4Pie(tableName, pieInfoDtoList, chartResultPojo, chartResultDetailVO);

    }

    /**
     * 客户分析--客户流失分析--流失前阶段分析
     * 客户阶段转化率（排除成交及成交之后阶段，只包含普通阶段）：该阶段后面所有阶段客户总数除以 从当前阶段开始的所有客户数 作为该阶段的转化率。
     * 比如，假设总共有5个阶段，阶段1的转化率=阶段(2+3+4+5)数/5个阶段总数；阶段2的转化率=(3+4+5)数/5个阶段总数，以此类推
     * 客户阶段平均停留时长（不计算流失和成交及之后所有阶段，只计算普通阶段）
     * 分两种情况：
     * （1）客户还处于该阶段，则按照截至到nowTime（当前时间）减去进入该阶段的时间，差值即停留时长；
     * （2）客户已经改到下面的阶段，则直接按照离开阶段的时间减去进入到该阶段时的时间，差值即停留时长。
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author youli.chen
     * @date 2019/3/11 19:31
     * @since v1.0
     * @version v1.0
     */
    public Object customerBeforeStage(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO, String tableName) throws XbbException {
        //所有客户
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        ThroughDTO allThroughDTO = new ThroughDTO(chartResultPojo, systemCodeEnum);
        List<ResultDataSeriesChartVO> list = loseCustomerBeforeStage(chartResultPojo);

        StatisticResultPieInfoDTO allStatisticResultPieInfoDto = new StatisticResultPieInfoDTO(I18nMessageUtil.getMessage(I18nStringConstant.CUSTOMER_LOSE_BEFORE_STAGE), list, allThroughDTO);
        List<StatisticResultPieInfoDTO> pieInfoDtoList = Collections.singletonList(allStatisticResultPieInfoDto);

        return systemChartHelp.packageResult4Pie(tableName, pieInfoDtoList, chartResultPojo, chartResultDetailVO);

    }
    /**
     * 跟进客户区域分布
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @author zcp
     * @date 2019/2/25 19:35
     * @since v1.0
     * @version v1.0
     */
    public Object customerFollowMap(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_FOLLOW_CHART_MAP);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ChartResultDetailVO redisChartResultDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultDetailVO.class);
        if (Objects.nonNull(redisChartResultDetailVO)) {
            return redisChartResultDetailVO;
        }
        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", chartResultPojo.getCorpid()));
        //从跟进记录中获取跟进的客户id
        chartQueryHelp.getFollowIdfromCommunicate(XbbRefTypeEnum.CUSTOMER_MANAGEMENT, chartResultPojo, boolQueryBuilder, true);
        //地图
        List<ResultDataSeriesChartVO> list = systemChartHelp.getCustomerDrawRegionMap(chartResultPojo, boolQueryBuilder);
        //地图不穿透
        ThroughDTO throughDto = null;
        StatisticResultPieInfoDTO statisticResultPieInfoDto = new StatisticResultPieInfoDTO("跟进客户区域分布", list, throughDto);
        List<StatisticResultPieInfoDTO> pieInfoDtoList = Collections.singletonList(statisticResultPieInfoDto);
        redisChartResultDetailVO = systemChartHelp.packageResult4Map("客户数量", pieInfoDtoList, chartResultPojo, chartResultDetailVO);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisChartResultDetailVO, RedisTimeConstant.TINY_DURATION);
        return redisChartResultDetailVO;
    }
    /**
     * 跟进客户数、成交跟进客户数
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/25 21:01
     * @since v1.0
     * @version v1.0
     */
    public Object customerFollowOkChartCompared(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ResultCountListVO followResultCountListVO = customerFollow2ResultCountListVO(chartResultPojo);
        ResultCountListVO okFollowResultCountListVO = customerFollowOk2ResultCountListVO(chartResultPojo);
        List<Integer> followResult = followResultCountListVO.getResultList();
        List<Integer> okFollowResult = okFollowResultCountListVO.getResultList();

        ElasticAggsPojo followElasticAggsPojo = new ElasticAggsPojo();
        ElasticAggsPojo okFollowElasticAggsPojo = new ElasticAggsPojo();
        List<AggsBucketsPojo> followList = followElasticAggsPojo.getBuckets();
        List<AggsBucketsPojo> okFollowList = okFollowElasticAggsPojo.getBuckets();
        for (int i = 0; i < followResult.size(); i++) {
            String follwoCount = String.valueOf(followResult.get(i));
            String okFollwoCount = String.valueOf(okFollowResult.get(i));
            AggsBucketsPojo followPojo = new AggsBucketsPojo("", follwoCount);
            AggsBucketsPojo okFollowPojo = new AggsBucketsPojo("", okFollwoCount);
            followList.add(followPojo);
            okFollowList.add(okFollowPojo);
        }
        followElasticAggsPojo.setBuckets(followList);
        okFollowElasticAggsPojo.setBuckets(okFollowList);

        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_FOLLOW_BOARD);
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = ReportTargetEnum.COUNT_FOLLOW_CUSTOMER.getName();
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = false;
        StatisticResultInfoDTO followStatisticResultInfoDto = new StatisticResultInfoDTO(throughDto, tableFlag, 0, 0, legend, unit, followElasticAggsPojo);
        //置入跟进成交客户code（穿透需要指定指标类型）
        ThroughDTO throughDtoFollowOk = new ThroughDTO(chartResultPojo, SystemCodeEnum.CUSTOMER_FOLLOW_OK);
        legend = I18nMessageUtil.getMessage(ChartI18Constant.CUSTOMRE_FOLLOW_UP_TRANSACTIONS);
        StatisticResultInfoDTO okFollowStatisticResultInfoDto = new StatisticResultInfoDTO(throughDtoFollowOk, tableFlag, 0, 0, legend, unit, okFollowElasticAggsPojo);
        List<StatisticResultInfoDTO> statisticResultInfoDtoList = Arrays.asList(followStatisticResultInfoDto, okFollowStatisticResultInfoDto);
        StatisticResultDTO statisticResultDto = new StatisticResultDTO(totalFlag, "", null, statisticResultInfoDtoList);
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }
    /**
     * 客户成交跟进比
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/2/25 21:28
     * @since v1.0
     * @version v1.0
     */
    public Object customerFollowRate(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ResultCountListVO followResultCountListVO = customerFollow2ResultCountListVO(chartResultPojo);
        List<Integer> followResult = followResultCountListVO.getResultList();
        ResultCountListVO okFollowResultCountListVO = customerFollowOk2ResultCountListVO(chartResultPojo);
        List<Integer> okFollowResult = okFollowResultCountListVO.getResultList();

        ElasticAggsPojo elasticAggsPojo = new ElasticAggsPojo();
        List<AggsBucketsPojo> rateList = elasticAggsPojo.getBuckets();
        for (int i = 0; i < followResult.size(); i++) {
            Integer follwoCount = followResult.get(i);
            Integer okFollwoCount = okFollowResult.get(i);
            //成交比例
            double rate = ChartResultUtil.getRate(okFollwoCount, follwoCount);
            AggsBucketsPojo ratePojo = new AggsBucketsPojo("", rate + "%");
            rateList.add(ratePojo);
        }
        elasticAggsPojo.setBuckets(rateList);

        ThroughDTO throughDTO = null;
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = I18nMessageUtil.getMessage(I18nStringConstant.FOLLOW_UP_RATIO);
        String unit = "%";
        Boolean totalFlag = false;
        String valueTitle = null;
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 遗忘客户（一周到两周未联系客户）
     *
     * @param chartResultPojo
     * @return java.lang.String
     * @author 徐俊杰
     * @date 2019/2/26 20:56
     * @since v1.0
     */
    public String customerForgetBoard(ChartResultPojo chartResultPojo) throws XbbException {
        //时间范围（最后跟进时间）
        String fieldTime = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.LAST_CONNECT_TIME);
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        //customerQuery4Forget方法内有重新设置chartResultPojo的开始、结束时间
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, systemCodeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        if (StringUtil.isNotEmpty(redisResult)) {
            return redisResult;
        }
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Forget(systemCodeEnum, chartResultPojo, fieldTime);
        IndexTypeEnum customerIndex = indexTypeModel.getIndexType(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(customerIndex, boolQueryBuilder, null);
        redisResult = elasticAggsPojo.getTotal();
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisResult, RedisTimeConstant.TINY_DURATION);
        return redisResult;
    }

    /**
     * 客户全景图--未联系天数
     * @param panoramaPojo
     * @return java.lang.String
     * @throws XbbException
     * @author zcp
     * @date 2019/6/3 14:41
     * @since v1.0
     * @version v1.0
     */
    public String panoramaCustomerForget(PanoramaPojo panoramaPojo) throws XbbException {
        //获取一个客户
        CustomerEntityExt entity = customerModel.getByKey(panoramaPojo.getDataId(), panoramaPojo.getCorpid());
        if (entity == null) {
            throw new XbbException(CustomerErrorCodeEnum.API_ERROR_201001, CustomerErrorCodeEnum.API_ERROR_201001.getMsg());
        }
        JSONObject data = JsonHelperUtil.getJSONObject(entity.getData());
        //时间范围（最后跟进时间）
        String lastConnectTimeAttr = CustomerManagementEnum.LAST_CONNECT_TIME.getAttr();
        Long lastConnectTime = data.getLong(lastConnectTimeAttr);
        String day = DateTimeUtil.getLastConnectDay(lastConnectTime);
        return day;
    }

    /**
     * 跟进客户数
     *
     * @param chartResultPojo     入参，包含公司id，员工id、时间和部门筛选信息
     * @param chartResultDetailVO 出参
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/3/2 9:38
     * @since v1.0
     */
    public Object customerFollowHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //获取数组
        ElasticAggsPojo elasticAggsPojo = customerFollow2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        //获取总值
        ElasticAggsPojo elasticAggsPojoTotal = customerFollow2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE);
        elasticAggsPojo.setTotal(elasticAggsPojoTotal.getTotal());
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = ReportTargetEnum.COUNT_FOLLOW_CUSTOMER.getName();
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.EACH));
        Boolean totalFlag = true;
        String valueTitle = ReportTargetEnum.COUNT_FOLLOW_CUSTOMER.getName();
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 跟进客户数（首页看板）
     *
     * @param chartResultPojo
     * @return java.lang.String
     * @author 徐俊杰
     * @date 2019/3/12 17:02
     * @since v1.0
     */
    public String customerFollowBoard(ChartResultPojo chartResultPojo) throws XbbException {
        //ES获取跟进客户数
        ElasticAggsPojo elasticAggsPojo = customerFollow2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE);
        return elasticAggsPojo.getTotal();
    }

    /**
     * 新增客户数pk
     * @param userEntity 登录员工信息
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 16:10
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkCustomerAdd(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        //PK_CUSTOMER_ADD、PERFORMANCE_CUSTOMER_ADD共用一份缓存
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPkPojo, SystemCodeEnum.PK_CUSTOMER_ADD);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ChartResultPkDetailVO redisChartResultPkDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultPkDetailVO.class);
        if (Objects.nonNull(redisChartResultPkDetailVO)) {
            return redisChartResultPkDetailVO;
        }
        /*--------处理查询条件--------*/
        String fieldTime = "addTime";
        //表本身的createId不能变更，因此在data字典内增加创建人key
        String fieldGroup = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.CREATOR);
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Create(false, chartResultPkPojo, fieldTime);
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field(fieldGroup);
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        int pkType = chartResultPkPojo.getPkType();
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPkPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        redisChartResultPkDetailVO = pkHelp.getPkResult4Count(userEntity, chartResultPkPojo, chartResultPkDetailVO, customerIndex, boolQueryBuilder, termsAggregationBuilder, pkType);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisChartResultPkDetailVO, RedisTimeConstant.TINY_DURATION);
        return redisChartResultPkDetailVO;
    }

    /**
     * 新增客户数pk
     * @param userEntity 登录员工信息
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 16:10
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkRuleCustomerAdd(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        //PK_CUSTOMER_ADD、PERFORMANCE_CUSTOMER_ADD共用一份缓存
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPkPojo, SystemCodeEnum.PK_CUSTOMER_ADD, RedisConstant.PK_RULE);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ChartResultPkDetailVO redisChartResultPkDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultPkDetailVO.class);
        if (Objects.nonNull(redisChartResultPkDetailVO)) {
            return redisChartResultPkDetailVO;
        }
        /*--------处理查询条件--------*/
        String fieldTime = "addTime";
        //表本身的createId不能变更，因此在data字典内增加创建人key
        String fieldGroup = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.CREATOR);
        BoolQueryBuilder boolQueryBuilder = chartRuleQueryHelp.customerQuery4Create(true, chartEntity, chartResultPkPojo, fieldTime);
        // chartRuleQueryHelp.formOpenBase(boolQueryBuilder, chartResultPkPojo, XbbRefTypeEnum.CUSTOMER_MANAGEMENT);
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field(fieldGroup);
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        int pkType = chartResultPkPojo.getPkType();
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPkPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        redisChartResultPkDetailVO = pkRuleHelp.getPkResult4Count(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO, customerIndex, boolQueryBuilder, termsAggregationBuilder, pkType);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisChartResultPkDetailVO, RedisTimeConstant.TINY_DURATION);
        return redisChartResultPkDetailVO;
    }

    /**
     * 跟进客户数pk
     * @param userEntity 登录员工信息
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/19 20:32
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkRuleCustomerFollow(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        int pkType = chartResultPkPojo.getPkType();
        StringBuilder otherSuffix = new StringBuilder();
        otherSuffix.append(SymbolConstant.UNDERLINE);
        otherSuffix.append(RedisConstant.PK_RULE);
        otherSuffix.append(SymbolConstant.UNDERLINE);
        otherSuffix.append(pkType);
        //PK_CUSTOMER_FOLLOW、PERFORMANCE_CUSTOMER_FOLLOW共用一份缓存
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPkPojo, SystemCodeEnum.PK_CUSTOMER_FOLLOW, otherSuffix.toString());
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ChartResultPkDetailVO redisChartResultPkDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultPkDetailVO.class);
        if (Objects.nonNull(redisChartResultPkDetailVO)) {
            return redisChartResultPkDetailVO;
        }
        //塞入跟进记录相应查询条件，不限制创建人、限制开始时间
        BoolQueryBuilder boolQueryBuilder = chartRuleQueryHelp.communicateQuery4Base(true, chartEntity, chartResultPkPojo, true);
        //先以用户userId分组，然后以customerId分组
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field("creatorId.keyword");
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        //排重字段---客户id
        String fieldGroup = CustomerCommunicateEnum.getEsAttr4Keyword(CustomerCommunicateEnum.CUSTOMER_NAME);

        if (pkType == ChartConstant.PK_DEP) {
            /**
             部门pk时需要对customerId分组，得到各个桶内员工跟进的客户ids合集
             （因为求部门总跟进客户数时，不能直接对员工跟进数直接求和：可能不同人跟进同个客户）
             因此在对跟进客户的解析时，需要对部门pk的情况特殊处理
             */
            TermsAggregationBuilder subAggregationBuilder = AggregationBuilders.terms("aggs02").field(fieldGroup);
            subAggregationBuilder.size(Integer.MAX_VALUE);
            subAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
            termsAggregationBuilder.subAggregation(subAggregationBuilder);
        }else {
            //员工pk时，直接对customerId排重求出总数即可
            CardinalityAggregationBuilder cardinalityAggregationBuilder = AggregationBuilders.cardinality("aggs02").field(fieldGroup);
            termsAggregationBuilder.subAggregation(cardinalityAggregationBuilder);
        }
        redisChartResultPkDetailVO = pkRuleHelp.getPkResult4Count(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO, IndexTypeEnum.IDX_SAAS_CUSTOMER_COMMUNICATE, boolQueryBuilder, termsAggregationBuilder, pkType);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisChartResultPkDetailVO, RedisTimeConstant.TINY_DURATION);
        return redisChartResultPkDetailVO;
    }

    /**
     * 跟进客户数pk
     * @param userEntity 登录员工信息
     * @param chartResultPkPojo pk参数
     * @param chartResultPkDetailVO 塞入pk结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/19 20:32
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkCustomerFollow(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        int pkType = chartResultPkPojo.getPkType();
        StringBuilder otherSuffix = new StringBuilder();
        otherSuffix.append(SymbolConstant.UNDERLINE);
        otherSuffix.append(pkType);
        //PK_CUSTOMER_FOLLOW、PERFORMANCE_CUSTOMER_FOLLOW共用一份缓存
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPkPojo, SystemCodeEnum.PK_CUSTOMER_FOLLOW, otherSuffix.toString());
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ChartResultPkDetailVO redisChartResultPkDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultPkDetailVO.class);
        if (Objects.nonNull(redisChartResultPkDetailVO)) {
            return redisChartResultPkDetailVO;
        }
        //塞入跟进记录相应查询条件，不限制创建人、限制开始时间
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.communicateQuery4Base(false, chartResultPkPojo, true);
        //先以用户userId分组，然后以customerId分组
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field("creatorId.keyword");
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        //排重字段---客户id
        String fieldGroup = CustomerCommunicateEnum.getEsAttr4Keyword(CustomerCommunicateEnum.CUSTOMER_NAME);
        if (pkType == ChartConstant.PK_DEP) {
            /**
             部门pk时需要对customerId分组，得到各个桶内员工跟进的客户ids合集
             （因为求部门总跟进客户数时，不能直接对员工跟进数直接求和：可能不同人跟进同个客户）
             因此在对跟进客户的解析时，需要对部门pk的情况特殊处理
             */
            TermsAggregationBuilder subAggregationBuilder = AggregationBuilders.terms("aggs02").field(fieldGroup);
            subAggregationBuilder.size(Integer.MAX_VALUE);
            subAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
            termsAggregationBuilder.subAggregation(subAggregationBuilder);
        }else {
            //员工pk时，直接对customerId排重求出总数即可
            CardinalityAggregationBuilder cardinalityAggregationBuilder = AggregationBuilders.cardinality("aggs02").field(fieldGroup);
            termsAggregationBuilder.subAggregation(cardinalityAggregationBuilder);
        }
        redisChartResultPkDetailVO = pkHelp.getPkResult4Count(userEntity, chartResultPkPojo, chartResultPkDetailVO, IndexTypeEnum.IDX_SAAS_CUSTOMER_COMMUNICATE, boolQueryBuilder, termsAggregationBuilder, pkType);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, redisChartResultPkDetailVO, RedisTimeConstant.TINY_DURATION);
        return redisChartResultPkDetailVO;
    }

    //-------------------private方法-------------------
    /**
     * 客户总数or有效客户数：该方法获取出总数、和各个桶内数值list，不会封装成图表需要的数据格式
     * @param chartResultPojo
     * @param valueTypeEnum
     * @param systemCodeEnum 系统指标枚举，此方法只能传SystemCodeEnum.CUSTOMER_TOTAL_CHART，或者SystemCodeEnum.CUSTOMER_VALID_CHART
     * @param futureCalc 未来时间是否计算（如客户总数折线图，超过当前时间的，都用“--”标识，不再计算数量） 0否 1是，默认1计算
     * @return com.xbongbong.pro.statistic.pojo.vo.ResultCountListVO 客户总数vo
     * @throws XbbException
     * @author zcp
     * @date 2019/2/23 19:30
     * @since v1.0
     * @version v1.0
     */
    private ResultCountListVO customerTotal2ResultCountListVO(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum, SystemCodeEnum systemCodeEnum, int futureCalc) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = customerTotal2ElasticAggsPojo(chartResultPojo, valueTypeEnum, systemCodeEnum, futureCalc);
        return systemChartHelp.getResultCountListVO(elasticAggsPojo);
    }

    /**
     * 图表中心→经销商管理→订货分析
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author 魏铭
     * @date 2021/1/7 14：50
     * @since v1.0
     * @version v1.0
     */
    public Object salesAnalysis(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        String unit = chartResultPojo.getUnit();
        Integer numFormat = chartResultPojo.getNumFormat();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        //订单相关数据
        JSONObject orderResult =  systemChartHelp.orderForSales(chartResultPojo);
        JSONObject refundResult =  systemChartHelp.refundForSales(chartResultPojo);
        JSONArray orderBuckets = orderResult.getJSONArray("buckets");
        JSONArray refundBuckets = refundResult.getJSONArray("buckets");
        //第一个图和第二个图
        List<ResultChartVO> chart = new ArrayList<>();
        systemChartHelp.chartTwoForAnalysis(chartResultPojo, orderBuckets, refundBuckets, chart);
        JSONArray orderProductIds = orderResult.getJSONArray("orderProductIds");
        List<Integer> orderProductIdList = JSONObject.parseArray(orderProductIds.toJSONString(), Integer.class);
        JSONObject orderProductData = orderResult.getJSONObject("orderProductData");
        JSONObject orderProductMap = orderResult.getJSONObject("orderProductMap");
        JSONArray refundProductIds = orderResult.getJSONArray("refundProductIds");
        List<Integer> refundProductIdList = JSONObject.parseArray(refundProductIds.toJSONString(), Integer.class);
        JSONObject refundProductData = orderResult.getJSONObject("refundProductData");
        JSONObject returnProductMap = orderResult.getJSONObject("returnProductMap");
        //因为有4个图，所以要建4个ResultChartVO
        //热销商品排行top10
        ResultChartVO resultChartVO3 = new ResultChartVO();
        resultChartVO3.setName("热销商品排行TOP10");
        resultChartVO3.setTotalFlag(false);
        resultChartVO3.setChartType(ChartTypeEnum.BAR_CHART.getCode());
        List<ResultDataChartVO> data = new ArrayList<>();
        ResultDataChartVO resultDataChartVO = new ResultDataChartVO();
        List<String> top10Value1 = new ArrayList<>();
        List<String> xAxis = new ArrayList<>();
        if (!orderProductIdList.isEmpty()) {
            for (Integer integer : orderProductIdList) {
                Object o = orderProductData.get(integer);
                JSONObject jsonObject = JSON.parseObject(o.toString());
                //产品名称、产品规格、产品数量
                String productName = jsonObject.getString("productName");
                String specText = jsonObject.getString("specText");
                BigDecimal productNum = (BigDecimal)orderProductMap.get(integer);
                xAxis.add(productName+"-"+specText);
                top10Value1.add(productNum.toString());
            }
        }else{
            xAxis.add("暂无数据");
            top10Value1.add("0");
        }
        resultDataChartVO.setValue(JSONArray.parseArray(JSON.toJSONString(top10Value1)));
        resultDataChartVO.setUnit("订货数");
        resultDataChartVO.setDistributorMark(DistributorMarkEnum.DISTRIBUTOR.getCode());
        data.add(resultDataChartVO);
        resultChartVO3.setData(data);
        resultChartVO3.setXAxis(xAxis);
        //退货商品排行top10
        ResultChartVO resultChartVO4 = new ResultChartVO();
        resultChartVO4.setName("退货商品排行TOP10");
        resultChartVO4.setTotalFlag(false);
        resultChartVO4.setChartType(3);
        List<ResultDataChartVO> data4 = new ArrayList<>();
        ResultDataChartVO resultDataChartVO4 = new ResultDataChartVO();
        List<String> top10Value2 = new ArrayList<>();
        List<String> xAxis2 = new ArrayList<>();
        if (!refundProductIdList.isEmpty()) {
            for (Integer integer : refundProductIdList) {
                Object o = refundProductData.get(integer);
                JSONObject jsonObject = JSON.parseObject(o.toString());
                //产品名称、产品规格、产品数量
                String productName = jsonObject.getString("productName");
                String specText = jsonObject.getString("specText");
                BigDecimal productNum = (BigDecimal)returnProductMap.get(integer);
                xAxis2.add(productName+"-"+specText);
                top10Value2.add(String.valueOf(Math.abs(productNum.doubleValue())));
            }
        }else{
            xAxis2.add("暂无数据");
            top10Value2.add("0");
        }
        resultDataChartVO4.setValue(JSONArray.parseArray(JSON.toJSONString(top10Value2)));
        resultDataChartVO4.setUnit("退货数");
        resultDataChartVO4.setDistributorMark(DistributorMarkEnum.DISTRIBUTOR.getCode());
        data4.add(resultDataChartVO4);
        resultChartVO4.setXAxis(xAxis2);
        resultChartVO4.setData(data4);
        chart.add(resultChartVO3);
        chart.add(resultChartVO4);
        //封装各种指标数据
        //建立订单数、退货单数、订单金额、退货金额、金额合计、商品总数、退货商品总数、订单毛利、订单毛利率
        ThroughDTO orderthroughDTO  = new ThroughDTO(chartResultPojo, SystemCodeEnum.CONTRACT_DISTRIBUTOR_CHART);
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPojo.getFiscalYearTimePojo(), chartResultPojo.getStartTime(), chartResultPojo.getEndTime());
        ThroughDTO returnThroughDTO  = new ThroughDTO(chartResultPojo, SystemCodeEnum.REFUND_DISTRIBUTOR_CHART);
        ThroughDTO orderProductThroughDTO  = new ThroughDTO(chartResultPojo, SystemCodeEnum.ORDER_PRODUCT_DISTRIBUTOR_TABLE);
        ThroughDTO returnProductThroughDTO  = new ThroughDTO(chartResultPojo, SystemCodeEnum.RETURN_PRODUCT_DISTRIBUTOR_TABLE);
        ThroughDTO orderProfitThroughDTO  = new ThroughDTO(chartResultPojo, SystemCodeEnum.ORDER_PROFIT_DISTRIBUTOR_TABLE);
        ThroughDTO orderProfitRateThroughDTO  = new ThroughDTO(chartResultPojo, SystemCodeEnum.ORDER_PROFIT_RATE_DISTRIBUTOR_TABLE);
        List<JSONObject> search = chartResultPojo.getSearch();
        if (search != null) {
            JSONObject baseThrough1 = orderthroughDTO.getBaseThrough();
            baseThrough1.put("search", search);
            orderthroughDTO.setBaseThrough(baseThrough1);
            JSONObject baseThrough2 = returnThroughDTO.getBaseThrough();
            baseThrough2.put("search", search);
            orderthroughDTO.setBaseThrough(baseThrough2);
            JSONObject baseThrough3 = orderProductThroughDTO.getBaseThrough();
            baseThrough3.put("search", search);
            orderthroughDTO.setBaseThrough(baseThrough3);
            JSONObject baseThrough4 = returnProductThroughDTO.getBaseThrough();
            baseThrough4.put("search", search);
            orderthroughDTO.setBaseThrough(baseThrough4);
            JSONObject baseThrough5 = orderProfitThroughDTO.getBaseThrough();
            baseThrough5.put("search", search);
            orderthroughDTO.setBaseThrough(baseThrough5);
        }
        String orderThrough = throughHelp.getThrough(orderthroughDTO, timePojo);
        String returnThrough = throughHelp.getThrough(returnThroughDTO, timePojo);
        String orderProductThrough = throughHelp.getThrough(orderProductThroughDTO, timePojo);
        String returnProductThrough = throughHelp.getThrough(returnProductThroughDTO, timePojo);
        String orderProfitThrough = throughHelp.getThrough(orderProfitThroughDTO, timePojo);
        String orderProfitRateThrough = throughHelp.getThrough(orderProfitRateThroughDTO, timePojo);
        SingleValueVO singleValueVO1 = new SingleValueVO();
        singleValueVO1.setName("订单数");
        singleValueVO1.setThrough(orderThrough);
        singleValueVO1.setValue(orderResult.getString("total"));
        singleValueVO1.setJumpFlag(true);
        singleValueVO1.setUnit("个");
        SingleValueVO singleValueVO2 = new SingleValueVO();
        singleValueVO2.setName("退货单数");
        singleValueVO2.setThrough(returnThrough);
        singleValueVO2.setValue(refundResult.getString("total"));
        singleValueVO2.setJumpFlag(true);
        singleValueVO2.setUnit("个");
        SingleValueVO singleValueVO3 = new SingleValueVO();
        double tempContractAmount = orderResult.getDoubleValue("contractAmount");
        String contractAmount = ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(tempContractAmount), numFormatEnum);
        singleValueVO3.setName("订单金额");
        singleValueVO3.setThrough(orderThrough);
        singleValueVO3.setValue(contractAmount);
        singleValueVO3.setJumpFlag(true);
        singleValueVO3.setUnit(unit);
        SingleValueVO singleValueVO4 = new SingleValueVO();
        double tempRefundAmount = refundResult.getDoubleValue("refundAmount");
        String refundAmount = ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(tempRefundAmount), numFormatEnum);
        singleValueVO4.setName("退货金额");
        singleValueVO4.setThrough(returnThrough);
        singleValueVO4.setValue(refundAmount);
        singleValueVO4.setJumpFlag(true);
        singleValueVO4.setUnit(unit);
        SingleValueVO singleValueVO5 = new SingleValueVO();
        String totalAmount = ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(tempContractAmount-tempRefundAmount), numFormatEnum);
        singleValueVO5.setName("金额合计");
        singleValueVO5.setValue(totalAmount);
        singleValueVO5.setJumpFlag(false);
        singleValueVO5.setUnit(unit);
        SingleValueVO singleValueVO6 = new SingleValueVO();
        singleValueVO6.setName("销售商品数");
        singleValueVO6.setThrough(orderProductThrough);
        singleValueVO6.setValue(orderResult.getString("orderProductNum"));
        singleValueVO6.setJumpFlag(true);
        singleValueVO6.setUnit("个");
        SingleValueVO singleValueVO7 = new SingleValueVO();
        singleValueVO7.setName("退货商品数");
        singleValueVO7.setThrough(returnProductThrough);
        double tempNum = orderResult.getDouble("refundProductNum");
        String refundProductNum = attrDecimalPrecisionHelper.getNumberFormat(String.valueOf(tempNum), 2, null, null);
        singleValueVO7.setValue(refundProductNum);
        singleValueVO7.setJumpFlag(true);
        singleValueVO7.setUnit("个");
        SingleValueVO singleValueVO8 = new SingleValueVO();
        double contractProfit = orderResult.getDoubleValue("contractProfit");
        String orderProfit = ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(contractProfit), numFormatEnum);
        singleValueVO8.setName("订单毛利");
        singleValueVO8.setThrough(orderProfitThrough);
        singleValueVO8.setValue(orderProfit);
        singleValueVO8.setJumpFlag(true);
        singleValueVO8.setUnit(unit);
        SingleValueVO singleValueVO9 = new SingleValueVO();
        String profitRate = "";
        if (contractProfit == 0.0) {
            profitRate = "0.00%";
        }else{
            profitRate = attrDecimalPrecisionHelper.getNumberFormat(String.valueOf(contractProfit/tempContractAmount), 2, null, 1);
        }
        singleValueVO9.setName("订单毛利率");
        singleValueVO9.setThrough(orderProfitRateThrough);
        singleValueVO9.setValue(profitRate);
        singleValueVO9.setJumpFlag(true);
        List<SingleValueVO> singleValueVOS = new ArrayList<>();
        singleValueVOS.add(singleValueVO1);
        singleValueVOS.add(singleValueVO2);
        singleValueVOS.add(singleValueVO3);
        singleValueVOS.add(singleValueVO4);
        singleValueVOS.add(singleValueVO5);
        singleValueVOS.add(singleValueVO6);
        singleValueVOS.add(singleValueVO7);
        singleValueVOS.add(singleValueVO8);
        singleValueVOS.add(singleValueVO9);
        chartResultDetailVO.setChart(chart);
        chartResultDetailVO.setSingleValueVOS(singleValueVOS);
        return  chartResultDetailVO;
    }

    /**
     * 图表中心-经销商管理-发货分析
     * @param chartResultPojo  请求系统指标接口需要用到的pojo类（内部存系统指标统计时需要的参数）
     * @param chartResultDetailVO
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultDetailVO
     * @author weiming
     * @date 2020/1/13 20:49
     * @since v1.0
     * @version v1.0
     */
    public ChartResultDetailVO deliveryAnalysis(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //从这里判断是按订单还是按产品
        Integer byOrder = chartResultPojo.getByOrder();
        boolean byOrderOrProduct = Objects.equals(byOrder,1);
        //出库发货单的数量
        long orderResult = getOutstockCount(chartResultPojo, byOrderOrProduct);
        //发货商品数、发货金额、产品的一些数据和订单id
        getProduct4OutStock(chartResultPojo, chartResultDetailVO, orderResult, byOrderOrProduct);
        return chartResultDetailVO;
    }

    /**
     * @Description 发货分析页面出库发货单数
     * @param chartResultPojo
     * @param flag 按订单还是按产品的标识
     * @return long 发货单数
     * @author 魏铭
     * @Date  2021/1/29/14:19
     **/
    private long getOutstockCount(ChartResultPojo chartResultPojo, boolean flag) throws XbbException {
        String fieldTime = "addTime";
        //封装开始时间和结束时间
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4Time(chartResultPojo, fieldTime, true);
        //封装chartResultPojo中的search 查询条件封装销售出库单中的link_distributor  product
        if (flag){//TODO 按产品 ： 时间、经销商名称、产品名称
            //封装发货分析（按产品）的筛选条件
            //封装经销商名称 查询条件
            List<JSONObject> searchList = chartResultPojo.getSearch();
            if (CollectionsUtil.isNotEmpty(searchList)) {
                for (int i = 0; i < searchList.size(); i++) {
                    JSONObject jsonObject = searchList.get(i);
                    if (Objects.equals(OrderEnum.LINK_DISTRIBUTOR.getAttr(), jsonObject.getString("attr"))) {
                        ConditionsEntityExt condition = JSON.parseObject(jsonObject.toJSONString(), ConditionsEntityExt.class);
                        condition.setAttr(ContractOutstockEnum.getAttrConnectData(ContractOutstockEnum.LINK_CUSTOMER));
                        ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
                        EsUtil.symbolChoose4Distributor(boolQueryBuilder, conditionEnum, condition);
                    } else {
                        JSONArray values = jsonObject.getJSONArray("value");
                        List<Long> idList = JSON.parseArray(values.toJSONString(), Long.class);
                        boolQueryBuilder.filter(termsQuery(ContractOutstockEnum.getAttrConnectData(ContractOutstockEnum.PRODUCT), idList));
                    }
                }
            }
        }else{//TODO 按订单 ：时间、范围
            // 该表单的数据权限
            TransmittableThreadLocalUtil.setValue(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.ORDER_OUTSTOCK.getCode(), null, DistributorMarkEnum.DISTRIBUTOR.getCode());
            List<ConditionsEntityExt> conditionsList = new ArrayList<>();
            saasListDataPermissionHelp.listDataPermission(conditionsList,chartResultPojo.getLoginUser(), XbbRefTypeEnum.ORDER_OUTSTOCK.getCode(), XbbRefTypeEnum.ORDER_OUTSTOCK.getCode());
            if (CollectionUtils.isNotEmpty(conditionsList)){
                EsUtil.parseCondition(boolQueryBuilder,conditionsList,"",chartResultPojo.getCorpid(),XbbRefTypeEnum.ORDER_OUTSTOCK.getCode());
            }
        }
        /*--------得到聚合结果--------*/
        //ElasticAggsPojo elasticAggsPojo = esHelper.esForOrder1(indexTypeEnum, boolQueryBuilder, dateHistogramAggregation);
        //OrderEnum 临时用 ContractEnum
        //确定索引 在count方法封好了
        // TODO 出库发货单是否单模板 出库发货单的formIdList
        List<Long> formIdList = paasFormModel.getFormIdList4Distributor(
                XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode(),chartResultPojo.getCorpid(),1);
        boolQueryBuilder.filter(termsQuery("formId",formIdList));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //查询条件放到查询语句中
        sourceBuilder.size(0);
        sourceBuilder.query(boolQueryBuilder);
        long count = paasEsModel.count(boolQueryBuilder, IndexTypeEnum.IDX_SAAS_CONTRACT_OUTSTOCK);
        return count;
    }

    /**
     * @Description 发货分析页面除出库发货单数，其他所有数据
     * @param chartResultPojo, chartResultDetailVO, orderResult, flag
     * @return void
     * @author weiming
     * @Date  2021/1/29/14:19
     * @since
     **/
    public void getProduct4OutStock(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO, long orderResult, boolean flag) throws XbbException {
        String corpid = chartResultPojo.getCorpid();
        Integer page = chartResultPojo.getPage();
        Integer pageSize = chartResultPojo.getPageSize();
        String unit = chartResultPojo.getUnit();
        Integer numFormat = chartResultPojo.getNumFormat();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        BoolQueryBuilder parentBoolQueryBuilder = systemChartHelp.packageOrderSearch(chartResultPojo);
        //订单状态：待发货、待收货、已完成、已关闭。
        parentBoolQueryBuilder.filter(termsQuery(OrderEnum.getAttrConnectData(OrderEnum.STATUS), OrderStatusEnum.getCode4Statistics()));
        JSONObject productObject = new JSONObject();
        if (flag){//TODO 按产品 ： 时间、经销商名称、产品名称
            //封装经销商名称 查询条件
            List<JSONObject> searchList = chartResultPojo.getSearch();
            if (CollectionsUtil.isNotEmpty(searchList)) {
                for (int i = 0; i < searchList.size(); i++) {
                    JSONObject jsonObject = searchList.get(i);
                    if (Objects.equals(OrderEnum.LINK_DISTRIBUTOR.getAttr(), jsonObject.getString("attr"))) {
                        ConditionsEntityExt condition = JSON.parseObject(jsonObject.toJSONString(), ConditionsEntityExt.class);
                        condition.setAttr(OrderEnum.getAttrConnectData(OrderEnum.LINK_DISTRIBUTOR));
                        ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
                        EsUtil.symbolChoose4Distributor(parentBoolQueryBuilder, conditionEnum, condition);
                    }else{
                        productObject = jsonObject;
                    }
                }
            }
        }
        HasParentQueryBuilder hasParentQueryBuilder = JoinQueryBuilders.hasParentQuery(IndexTypeEnum.IDX_SAAS_CONTRACT.getType(), parentBoolQueryBuilder, false);
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        if (!productObject.isEmpty()){
            JSONArray values = productObject.getJSONArray("value");
            List<Long> idList = JSON.parseArray(values.toJSONString(), Long.class);
            boolQueryBuilder.filter(termsQuery(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID), idList));
        }
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del",0));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT.getType()));
        boolQueryBuilder.filter(termQuery("data.num_37", XbbRefTypeEnum.CONTRACT.getCode()));
        boolQueryBuilder.filter(hasParentQueryBuilder);
        //发货商品数
        SumAggregationBuilder agg01 = AggregationBuilders.sum("agg01")
                .field(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.SHIPMENTS_NUM));
        //发货金额 发货数量*单价
        boolQueryBuilder.filter(existsQuery(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.SHIPMENTS_NUM)));
        boolQueryBuilder.filter(existsQuery(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE)));
        SumAggregationBuilder agg02 = AggregationBuilders.sum("agg02")
                .script(new Script("doc['"+ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.SHIPMENTS_NUM)
                        +"'].value*doc['"+ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE)+"'].value"));
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        //EsUtil.setFieldList(sourceBuilder, fieldList);//要查哪些数据。
        EsUtil.setPage(sourceBuilder, page, pageSize);
        sourceBuilder.aggregation(agg01);
        sourceBuilder.aggregation(agg02);
        searchRequest.source(sourceBuilder);
        //查询并返回结果
        XbbAggregatedPage<PaasFormDataEntity> result = xbbElasticsearchRestTemplate.queryOfDistributor(searchRequest,PaasFormDataEntity.class);
        int rowCounts = 0;
        List<PaasFormDataEntity> list = null;
        if (result != null) {
            rowCounts = (int) result.getTotalElements();
            list = result.getContent();
        }
        List<ContractProductEntity> productList = transferSubFormHelper.transferFormDataToContractProductList(list);
        //formatChildSpecification(list, corpid);
        Set<Long> contractIdIn = new HashSet<>();
        List<String> fieldList = Arrays.asList("id", "dataId", OrderEnum.ORDER_NO.getAttr(),
                OrderEnum.getAttrConnectData(OrderEnum.LINK_DISTRIBUTOR), OrderEnum.getAttrConnectData(OrderEnum.LINK_CUSTOMER_HIDE),
                OrderEnum.getAttrConnectData(OrderEnum.SIGN_TIME));
        for (ContractProductEntity entity : productList) {
//            productIdIn.add(entity.getProductId());
            contractIdIn.add(entity.getContractId());
        }
        //根据contractIdList去查询contract数据。 Map<订单id,订单的数据>
        Map<Long, JSONObject> orderIdMap = formHelp.getOrderDataByIds4Distributor(null, corpid, IndexTypeEnum.IDX_SAAS_CONTRACT, contractIdIn, fieldList);
        ResultTableVO resultTableVO = new ResultTableVO();
        resultTableVO.setTableName("发货分析");
        List<TitleRightPojo> tempList = new ArrayList<>();
        if (!flag){
            TitleRightPojo titleRightPojo1  =new TitleRightPojo();
            titleRightPojo1.setTitleValue("订单编号");
            titleRightPojo1.setNumRight(2);
            tempList.add(titleRightPojo1);
            TitleRightPojo titleRightPojo2  =new TitleRightPojo();
            titleRightPojo2.setTitleValue("经销商名称");
            titleRightPojo2.setNumRight(2);
            tempList.add(titleRightPojo2);
        }
        TitleRightPojo titleRightPojo3  =new TitleRightPojo();
        titleRightPojo3.setTitleValue("产品名称");
        titleRightPojo3.setNumRight(2);
        tempList.add(titleRightPojo3);
        TitleRightPojo titleRightPojo4  =new TitleRightPojo();
        titleRightPojo4.setTitleValue("产品编码");
        titleRightPojo4.setNumRight(2);
        tempList.add(titleRightPojo4);
        TitleRightPojo titleRightPojo5  =new TitleRightPojo();
        titleRightPojo5.setTitleValue("规格");
        titleRightPojo5.setNumRight(2);
        tempList.add(titleRightPojo5);
        TitleRightPojo titleRightPojo6  =new TitleRightPojo();
        titleRightPojo6.setTitleValue("订购数量");
        titleRightPojo6.setNumRight(2);
        tempList.add(titleRightPojo6);
        TitleRightPojo titleRightPojo7  =new TitleRightPojo();
        titleRightPojo7.setTitleValue("已发货数量");
        titleRightPojo7.setNumRight(2);
        tempList.add(titleRightPojo7);
        TitleRightPojo titleRightPojo8  =new TitleRightPojo();
        titleRightPojo8.setTitleValue("未发货数量");
        titleRightPojo8.setNumRight(2);
        tempList.add(titleRightPojo8);
        TitleRightPojo titleRightPojo9  =new TitleRightPojo();
        titleRightPojo9.setTitleValue("已发货金额(" + unit + ")");
        titleRightPojo9.setNumRight(2);
        tempList.add(titleRightPojo9);
        TitleRightPojo titleRightPojo10  =new TitleRightPojo();
        titleRightPojo10.setTitleValue("未发货金额(" + unit + ")");
        titleRightPojo10.setNumRight(2);
        tempList.add(titleRightPojo10);
        resultTableVO.setTitle(tempList);
        List<List<TableDataInfoNewPojo>> businessData = new ArrayList<>();
        //遍历productList 封装数据
        for (ContractProductEntity entity : productList) {
            Long contractId = entity.getContractId();//订单id
            JSONObject orderObject = orderIdMap.get(contractId);//订单的信息
            Long distributorId = orderObject.getLong("distributorId");
            List<TableDataInfoNewPojo> tableDataInfoNewPojoList = new ArrayList<>();
            if (!flag){
                DataDetailTabPojo dataDetailTabPojo1 = new DataDetailTabPojo(contractId, 1, XbbRefTypeEnum.CONTRACT.getCode());// orderId,saasMark,BusinessType
                TableDataInfoNewPojo  tableDataInfoNewPojo1 = new TableDataInfoNewPojo(orderObject.getString("orderNo"),1, dataDetailTabPojo1);//订单编号
                tableDataInfoNewPojoList.add(tableDataInfoNewPojo1);
                DataDetailTabPojo dataDetailTabPojo2 = new DataDetailTabPojo(distributorId, 1, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
                TableDataInfoNewPojo  tableDataInfoNewPojo2 = new TableDataInfoNewPojo(orderObject.getString("distributorName"),1, dataDetailTabPojo2);//经销商名称
                tableDataInfoNewPojoList.add(tableDataInfoNewPojo2);
            }
            TableDataInfoNewPojo  dataDetailTabPojo3 = new TableDataInfoNewPojo(entity.getProductName());//产品名称
            TableDataInfoNewPojo  dataDetailTabPojo4 = new TableDataInfoNewPojo(entity.getProductNo());//产品编码
            TableDataInfoNewPojo  dataDetailTabPojo5;

            String specification = entity.getSpecification();
            try {
                JSONObject specObject = JSON.parseObject(specification);
                if (specObject == null) {
                    dataDetailTabPojo5 = new TableDataInfoNewPojo(specification);
                }else{
                    StringBuilder stringBuilder = new StringBuilder();
                    StringUtil.stringBuilderAppendSuffix(stringBuilder,"/",specObject.values().toArray());
                    dataDetailTabPojo5 = new TableDataInfoNewPojo(stringBuilder.toString());
                }
            } catch (JSONException e) {
                dataDetailTabPojo5 = new TableDataInfoNewPojo(specification);
            }
            //数量的格式化
            Double productNum = entity.getProductNum();
            Double shipmentsNum = entity.getShipmentsNum();
            String orderAmount = attrDecimalPrecisionHelper.getNumberFormat(productNum.toString(),0,null,null);
            String sendOutAmount = attrDecimalPrecisionHelper.getNumberFormat(shipmentsNum.toString(),0,null,null);
            //未发货数量 = 订购数量 - 已发货数量
            double waitSendNum = productNum - shipmentsNum;
            String waitSendAmount = attrDecimalPrecisionHelper.getNumberFormat(String.valueOf(waitSendNum),0,null,null);
            TableDataInfoNewPojo  dataDetailTabPojo6 = new TableDataInfoNewPojo(orderAmount);//订购数量
            TableDataInfoNewPojo  dataDetailTabPojo7 = new TableDataInfoNewPojo(sendOutAmount);//已发货数量 TODO 这里先拿已出库数量
            TableDataInfoNewPojo  dataDetailTabPojo8 = new TableDataInfoNewPojo(waitSendAmount);//未发货数量
            TableDataInfoNewPojo  dataDetailTabPojo9 = new TableDataInfoNewPojo(ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(shipmentsNum * entity.getPrice()), numFormatEnum));//已发货金额
            TableDataInfoNewPojo  dataDetailTabPojo10 = new TableDataInfoNewPojo(ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(waitSendNum * entity.getPrice()), numFormatEnum));//未发货金额

            tableDataInfoNewPojoList.add(dataDetailTabPojo3);
            tableDataInfoNewPojoList.add(dataDetailTabPojo4);
            tableDataInfoNewPojoList.add(dataDetailTabPojo5);
            tableDataInfoNewPojoList.add(dataDetailTabPojo6);
            tableDataInfoNewPojoList.add(dataDetailTabPojo7);
            tableDataInfoNewPojoList.add(dataDetailTabPojo8);
            tableDataInfoNewPojoList.add(dataDetailTabPojo9);
            tableDataInfoNewPojoList.add(dataDetailTabPojo10);
            businessData.add(tableDataInfoNewPojoList);
        }
        resultTableVO.setBusinessData(businessData);
        resultTableVO.setTableName("发货分析");
        resultTableVO.setChartType(chartResultPojo.getChartEntity().getChartType());
        resultTableVO.setSystemCode(chartResultPojo.getChartEntity().getSystemCode());
        PageHelper pageHelper = PageHelperUtil.initPageHelper(rowCounts, page, pageSize, pageSize);
        resultTableVO.setPageHelper(pageHelper);
        chartResultDetailVO.setTable(resultTableVO);
        //封装各种指标数据
        Aggregations aggregations = result.getAggregations();
        List<Aggregation> as = aggregations.asList();
        String outStockNum = null;
        String outStockAmount = null;
        for (Aggregation a : as) {
            Sum sum = (Sum) a;
            if ("agg01".equals(a.getName())) {
                outStockNum = sum.getValueAsString();
                outStockNum = attrDecimalPrecisionHelper.getNumberFormat(outStockNum, 0, null, null);
            }else {
                outStockAmount = sum.getValueAsString();
            }
        }
        List<SingleValueVO> singleValueVOS = new ArrayList<>();
        //建立订单数、退货单数、订单金额、退货金额、金额合计、商品总数、退货商品总数、订单毛利、订单毛利率
        SingleValueVO singleValueVO1 = new SingleValueVO();
        singleValueVO1.setValue(String.valueOf(orderResult));
        singleValueVO1.setName("出库发货单数");
        singleValueVO1.setUnit("个");
        singleValueVO1.setJumpFlag(false);
        SingleValueVO singleValueVO2 = new SingleValueVO();
        singleValueVO2.setValue(outStockNum);
        singleValueVO2.setName("发货商品数");
        singleValueVO2.setUnit("个");
        singleValueVO2.setJumpFlag(false);
        SingleValueVO singleValueVO3 = new SingleValueVO();
        singleValueVO3.setValue(ChartResultUtil.formatVal2Thousands(new BigDecimal(outStockAmount), numFormatEnum));
        singleValueVO3.setName("发货金额");
        singleValueVO3.setUnit(unit);
        singleValueVO3.setJumpFlag(false);
        singleValueVOS.add(singleValueVO1);
        singleValueVOS.add(singleValueVO2);
        singleValueVOS.add(singleValueVO3);
        chartResultDetailVO.setSingleValueVOS(singleValueVOS);
    }

    /**
     * 客户总数or有效客户数，计算截至到当前的方法（是否计算未来时间通过futureCalc控制），主要用于【客户总数、有效客户数的统计】
     * @param chartResultPojo 参数pojo
     * @param valueTypeEnum 数值类型
     * @param systemCodeEnum 系统指标枚举，此方法只能传SystemCodeEnum.CUSTOMER_TOTAL_CHART，或者SystemCodeEnum.CUSTOMER_VALID_CHART
     * @param futureCalc 未来时间是否计算（如客户总数折线图，超过当前时间的，都用“--”标识，不再计算数量） 0否 1是，默认1计算
     * @return com.xbongbong.paas.elasticsearch.pojo.vo.ElasticAggsPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/2/20 9:49
     * @since v1.0
     * @version v1.0
     */
    private ElasticAggsPojo customerTotal2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum, SystemCodeEnum systemCodeEnum, int futureCalc) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, systemCodeEnum, valueTypeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String value = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ElasticAggsPojo result;
        if (value != null) {
            try {
                result = JsonHelperUtil.parseObject(value, ElasticAggsPojo.class);
                return result;
            } catch (Exception e) {
                //不作处理  解析异常走正常查询逻辑更新缓存
            }
        }
        String fieldTime = "addTime";
        //不计算未来时间
        chartResultPojo.setFutureCalc(futureCalc);
        /*--------处理查询条件：先处理时间段内的所有客户数--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Team(chartResultPojo, fieldTime, true);
        if (systemCodeEnum == SystemCodeEnum.CUSTOMER_VALID_CHART) {
            String corpid = chartResultPojo.getCorpid();
            //有效客户限制有效客户状态：所有启用的客户状态内，排除“无效客户”的客户状态即为全部有效客户状态
            Set<String> typeIn = commonHelp.getCustomerTypeIn4Valid(corpid);
            boolQueryBuilder.filter(termsQuery(CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.TYPE), typeIn));
        }
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        ElasticAggsPojo elasticAggsPojo = systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, customerIndex, boolQueryBuilder, fieldTime);
        /*--------再获取出截至到startTime的所有客户数--------*/
        //移除addTime，重新塞入新的条件
        esHelper.removeSearchCondition(boolQueryBuilder, fieldTime);
        int startTime = chartResultPojo.getStartTime();
        boolQueryBuilder.filter(rangeQuery(fieldTime).lt(startTime));
        Integer pastTotal = systemChartHelp.getCount4Total(customerIndex, boolQueryBuilder);
        //处理结果
        result = ChartResultUtil.totalAggs(elasticAggsPojo, pastTotal, valueTypeEnum, chartResultPojo, futureCalc);
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, result, TimeConstant.TINY_DURATION);
        return result;
    }
    /**
     * 获取客户日活、月活数
     * @param chartResultPojo 参数pojo
     * @param valueTypeEnum 数值类型
     * @return com.xbongbong.paas.elasticsearch.pojo.vo.ElasticAggsPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/2/20 17:11
     * @since v1.0
     * @version v1.0
     */
    private ElasticAggsPojo customerActive2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_ACTIVE_CHART_DAY, valueTypeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ElasticAggsPojo elasticAggsPojo = JsonHelperUtil.parseObject(redisResult, ElasticAggsPojo.class);
        if (Objects.nonNull(elasticAggsPojo)) {
            return elasticAggsPojo;
        }
        //时间范围
        String lastConnectTime = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.LAST_CONNECT_TIME);
        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Team(chartResultPojo, lastConnectTime, true);

        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        elasticAggsPojo = systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, customerIndex, boolQueryBuilder, lastConnectTime);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, elasticAggsPojo, RedisTimeConstant.TINY_DURATION);
        return elasticAggsPojo;
    }

    /**
     * 新增客户数，返回结果为ElasticAggsPojo
     * @param chartResultPojo
     * @param valueTypeEnum
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/2/24 10:35
     * @since v1.0
     * @version v1.0
     */
    private ElasticAggsPojo customerAdd2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        //该指标缓存统一用SystemCodeEnum.CUSTOMER_ADD_CHART标识
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_ADD_CHART, valueTypeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String value = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);

        if (!chartResultPojo.isReadCache()) {
            value = null;
        }

        ElasticAggsPojo result;
        if (value != null) {
            try {
                result = JsonHelperUtil.parseObject(value, ElasticAggsPojo.class);
                return result;
            } catch (Exception e) {
                //不作处理  解析异常走正常查询逻辑更新缓存
            }
        }
        /*--------处理查询条件--------*/
        String fieldTime = "addTime";
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Create(true, chartResultPojo, fieldTime);
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        result = systemChartHelp.getCount4Agg(chartResultPojo, valueTypeEnum, customerIndex, boolQueryBuilder, fieldTime);
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, result, TimeConstant.TINY_DURATION);
        return result;
    }
    /**
     * 获取成交客户的id合集（总数返回id合集，各个桶也是id合集）
     * @param chartResultPojo
     * @return com.xbongbong.pro.statistic.pojo.FloorAggsKeyPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/2/25 20:15
     * @since v1.0
     * @version v1.0
     */
    private FloorAggsKeyPojo customerOk2ElasticAggsPojo(ChartResultPojo chartResultPojo) throws XbbException {
        /*--------处理查询条件--------*/
        BoolQueryBuilder contractQueryBuilder = chartQueryHelp.customerOkQuery(chartResultPojo, true);
        //时间聚合字段
        String fieldTime = ContractEnum.getEsAttr4Keyword(ContractEnum.SIGN_TIME);
        //排重字段
        String fieldGroup = ContractEnum.getEsAttr4Keyword(ContractEnum.LINK_CUSTOMER);
        //移除formId，成交客户不限制合同的formId
        esHelper.removeSearchCondition(contractQueryBuilder, "formId");
        FloorAggsKeyPojo floorAggsKeyPojo = systemChartHelp.getFloorAggsKey(chartResultPojo, IndexTypeEnum.IDX_SAAS_CONTRACT, contractQueryBuilder, fieldTime, fieldGroup, true);
        return floorAggsKeyPojo;
    }
    /**
     * 同时计算出首次、再次成交客户
     * @param chartResultPojo 参数pojo
     * @param valueTypeEnum 数值类型
     * @return com.xbongbong.pro.statistic.pojo.CustomerOkFirstSecondPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/2/23 14:13
     * @since v1.0
     * @version v1.0
     */
    private CustomerOkFirstSecondPojo customerOkFirstSecond(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        //都是计算首次、再次成交客户数，且首次、再次是一次性都算出来的，因此缓存key用首次或再次的systemCode作为唯一标识都可以
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_OK_HOME_FIRST, valueTypeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        CustomerOkFirstSecondPojo customerOkFirstSecondPojo = JsonHelperUtil.parseObject(redisResult, CustomerOkFirstSecondPojo.class);
        if (Objects.nonNull(customerOkFirstSecondPojo)) {
            return customerOkFirstSecondPojo;
        }
        //先获取出截至到startTime的customerIdIn，用来判断首次成交用
        Set<Long> agoToStartCustomerIdIn = formHelp.getAgoToStartCustomerIdIn(chartResultPojo);
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CONTRACT;

        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerOkQuery(chartResultPojo, true);

        customerOkFirstSecondPojo = systemChartHelp.firstAndSecondAggregations(chartResultPojo, indexTypeEnum, boolQueryBuilder, agoToStartCustomerIdIn, valueTypeEnum);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, customerOkFirstSecondPojo, RedisTimeConstant.TINY_DURATION);
        return customerOkFirstSecondPojo;
    }
    /**
     *
     * 同时计算出首次、再次成交客户
     * @param chartResultPojo 参数pojo
     * @param valueTypeEnum 数值类型
     * @return com.xbongbong.pro.statistic.result.pojo.CustomerOkFirstSecondPojo
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private CustomerOkFirstSecondPojo customerOkFirstSecondRefactor(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        //都是计算首次、再次成交客户数，且首次、再次是一次性都算出来的，因此缓存key用首次或再次的systemCode作为唯一标识都可以
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_OK_HOME_SECOND, valueTypeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        CustomerOkFirstSecondPojo customerOkFirstSecondPojo = JsonHelperUtil.parseObject(redisResult, CustomerOkFirstSecondPojo.class);
        if (Objects.nonNull(customerOkFirstSecondPojo)) {
            return customerOkFirstSecondPojo;
        }
        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerOkQuery(chartResultPojo, true);
        customerOkFirstSecondPojo = systemChartHelp.firstAndSecondAggregations(chartResultPojo, boolQueryBuilder, valueTypeEnum);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, customerOkFirstSecondPojo, RedisTimeConstant.TINY_DURATION);
        return customerOkFirstSecondPojo;
    }
    /**
     * 流失客户
     * @param chartResultPojo
     * @return com.xbongbong.pro.statistic.pojo.vo.ResultCountListVO
     * @throws XbbException
     * @author zcp
     * @date 2019/2/23 17:07
     * @since v1.0
     * @version v1.0
     */
    private ResultCountListVO customerLose2ResultCountListVO(ChartResultPojo chartResultPojo) throws XbbException {
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_LOSE);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ResultCountListVO resultCountListVO = JsonHelperUtil.parseObject(redisResult, ResultCountListVO.class);
        if (Objects.nonNull(resultCountListVO)) {
            return resultCountListVO;
        }
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());


        /*--------处理查询条件--------*/
        //此处用updateTime,因为客户可能是很早添加的，后来转为无效。后续可能会有一个客户状态变更表，用来标记客户状态变更记录
        String fieldTime = "updateTime";
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Lose(chartResultPojo);

        ElasticAggsPojo elasticAggsPojo = systemChartHelp.getCount4Agg(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, customerIndex, boolQueryBuilder, fieldTime);
        resultCountListVO = systemChartHelp.getResultCountListVO(elasticAggsPojo);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, resultCountListVO, RedisTimeConstant.TINY_DURATION);
        return resultCountListVO;
    }

    /**
     * 客户画像：行业、来源、状态、地图
     * @param chartResultPojo 参数
     * @param dictionaryEnum 数据字典枚举，地图无需传该值
     * @param attrEnum 客户字段枚举，地图无需传该值
     * @param okFlag true成交客户，fals非成交
     * @param mapFlag true地图，fals非地图
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.vo.ResultDataSeriesChartVO>
     * @throws XbbException
     * @author zcp
     * @date 2019/2/24 21:13
     * @since v1.0
     * @version v1.0
     */
    private List<ResultDataSeriesChartVO> customerDraw(ChartResultPojo chartResultPojo, DictionaryEnum dictionaryEnum, CustomerManagementEnum attrEnum, boolean okFlag, boolean mapFlag) throws XbbException {
        //业务模版筛选
        Long templateId = chartResultPojo.getRefId();
        //非地图筛选的客户画像、且字典类型不是全公司基本的，需要传表单id
        boolean formIdFlag = !mapFlag && (templateId == null || templateId <= 0);
        if (formIdFlag && dictionaryEnum.getDictionaryTermEnum() != DictionaryTermEnum.DATA_DICTIONARY_TERM) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, String.format(StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(CommonConstant.FORM)));
        }
        String corpid = chartResultPojo.getCorpid();
        /*--------处理查询条件--------*/
        //时间范围，限制开始结束时间
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Team(chartResultPojo, "addTime", true);
        //okFlag为true时，则代表成交客户，需要置入成交客户id条件
        if (okFlag) {
            //从合同中获取成交的客户id
            chartQueryHelp.getDealCustomerIdfromContract(chartResultPojo, boolQueryBuilder, true);
        }
        if (mapFlag) {
            //地图
            return systemChartHelp.getCustomerDrawRegionMap(chartResultPojo, boolQueryBuilder);
        }else {
            //聚合字段，如行业、来源、状态
            String fieldGroup = CustomerManagementEnum.getEsAttr4Keyword(attrEnum);
            //查询出字典list
            List<ItemPoJo> dictionaryList = dataDictionaryModel.getDictionaryList4Saas(dictionaryEnum, corpid, templateId);
            IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

            return systemChartHelp.getDataDictionaryDataSeries(customerIndex, boolQueryBuilder, fieldGroup, dictionaryList);
        }
    }

    /**
     * 流失原因分析
     * @param chartResultPojo 参数
     * @param dictionaryEnum 数据字典枚举，地图无需传该值
     * @param attrEnum 客户字段枚举，地图无需传该值
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.vo.ResultDataSeriesChartVO>
     * @throws XbbException
     * @author youli.chen
     * @date 2019/2/24 21:13
     * @since v1.0
     * @version v1.0
     */
    private List<ResultDataSeriesChartVO> customerLose(ChartResultPojo chartResultPojo, DictionaryEnum dictionaryEnum, CustomerManagementEnum attrEnum) throws XbbException {
        String corpid = chartResultPojo.getCorpid();
        //业务模版筛选
        Long formId = chartResultPojo.getRefId();
        if (formId == null || formId == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, String.format(StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(CommonConstant.FORM)));
        }
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQueryBaseForLose(chartResultPojo, true, null, true);

        //聚合字段，如行业、来源、状态
        String fieldGroup = CustomerManagementEnum.getEsAttr4Keyword(attrEnum);
        //查询出字典list
        List<ItemPoJo> dictionaryList = dataDictionaryModel.getDictionaryList4Saas(dictionaryEnum, corpid, formId);
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        return systemChartHelp.getDataDictionaryDataSeries(customerIndex, boolQueryBuilder, fieldGroup, dictionaryList);
    }

    /**
     * 流失前阶段
     * @param chartResultPojo 参数
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.vo.ResultDataSeriesChartVO>
     * @throws XbbException
     * @author youli.chen
     * @date 2019/2/24 21:13
     * @since v1.0
     * @version v1.0
     */
    private List<ResultDataSeriesChartVO> loseCustomerBeforeStage(ChartResultPojo chartResultPojo) throws XbbException {
        String corpid = chartResultPojo.getCorpid();
        //业务模版筛选
        Long formId = chartResultPojo.getRefId();
        if (formId == null || formId == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, String.format(StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(CommonConstant.FORM)));
        }

        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQueryBaseForLose(chartResultPojo, true, null, false);
        IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());

        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, customerIndex.getType()));

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        List<String> fieldList = Arrays.asList(FieldTypeEnum.DATAID.getAlias());
        String[] strings = new String[fieldList.size()];
        sourceBuilder.fetchSource(fieldList.toArray(strings),null);

        SearchRequest searchRequest = new SearchRequest(customerIndex.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 0, PaasConstant.ES_MAX_PAGE_SIZE);
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);

        // es中当前流失的客户id
        List<Long> esLoseCustomerIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (esEntities == null) {
            esLoseCustomerIdList.add(-1L);
        }
        List<PaasFormDataEntityExt> list = esEntities.getContent();
        if(!list.isEmpty()){
            list.forEach(item -> esLoseCustomerIdList.add(item.getDataId()));
        } else {
            esLoseCustomerIdList.add(-1L);
        }

        // 直接去数据库进行分组统计
        Map<String, Integer> stageStatisticMap = customerStageLogModel.getStageStatistic(formId, corpid, esLoseCustomerIdList);

        List<ItemPoJo> dictionaryList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        StageFindStrategy stageFindStrategy = StageFindFactory.getStageFindStrategy(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        List<? extends PaasStageEntity> stageList = stageFindStrategy.findStageListSpecial(corpid, new StageFindPojo(formId, chartResultPojo.getArgTwoId()));
        for(PaasStageEntity stage : stageList){
            String stageCode = stage.getCode();
            if(Objects.equals(stage.getType(), StageTypeEnum.FAIL_STAGE.getType())){
                continue;
            }
            ItemPoJo itemPoJo = new ItemPoJo();
            itemPoJo.setText(stage.getName());
            Integer count = stageStatisticMap.get(stageCode) == null ? BasicConstant.ZERO : stageStatisticMap.get(stageCode);
            itemPoJo.setValue(count);
            itemPoJo.setCode(stageCode);
            dictionaryList.add(itemPoJo);
        }

        List<ResultDataSeriesChartVO> resultDataSeriesChartVOList = new ArrayList<>();
        for (ItemPoJo itemPojo : dictionaryList) {
            String code = itemPojo.getValue().toString();
            String realName = itemPojo.getText();
            String name = realName + "[" + code + "]" + I18nMessageUtil.getMessage(CommonConstant.EACH);
            ResultDataSeriesChartVO resultDataSeriesChartVO = new ResultDataSeriesChartVO();
            resultDataSeriesChartVO.setName(name);
            resultDataSeriesChartVO.setRealName(realName);
            resultDataSeriesChartVO.setCode(itemPojo.getCode());
            resultDataSeriesChartVO.setValue(code);
            resultDataSeriesChartVOList.add(resultDataSeriesChartVO);
        }
        return resultDataSeriesChartVOList;
    }



    /**
     * 跟进客户数：该方法获取出总数、和各个桶内数值list，不会封装成图表需要的数据格式
     * @param chartResultPojo
     * @return com.xbongbong.pro.statistic.pojo.vo.ResultCountListVO
     * @author zcp
     * @date 2019/2/25 19:54
     * @since v1.0
     * @version v1.0
     */
    private ResultCountListVO customerFollow2ResultCountListVO(ChartResultPojo chartResultPojo) throws XbbException {
        ElasticAggsPojo elasticAggsPojo = customerFollow2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE);
        return systemChartHelp.getResultCountListVO(elasticAggsPojo);
    }
    /**
     * 跟进客户
     * @param chartResultPojo
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @author zcp
     * @date 2019/2/25 19:55
     * @since v1.0
     * @version v1.0
     */
    private ElasticAggsPojo customerFollow2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum) throws XbbException {
        //跟进客户统一用SystemCodeEnum.CUSTOMER_FOLLOW_BOARD作为缓存唯一标识
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_FOLLOW_BOARD, valueTypeEnum);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);

        if (!chartResultPojo.isReadCache()) {
            redisResult = null;
        }

        ElasticAggsPojo elasticAggsPojo = JsonHelperUtil.parseObject(redisResult, ElasticAggsPojo.class);
        if (Objects.nonNull(elasticAggsPojo)) {
            return elasticAggsPojo;
        }
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.communicateQuery4UserLimitStart(chartResultPojo);
        String fieldTime = CustomerCommunicateEnum.getEsAttr4Keyword(CustomerCommunicateEnum.COMMUNICATE_TIME);
        //排重字段---客户id
        String fieldGroup = CustomerCommunicateEnum.getEsAttr4Keyword(CustomerCommunicateEnum.CUSTOMER_NAME);
        //用关联客户id聚合结果
        elasticAggsPojo = systemChartHelp.distinctAggregations(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_CUSTOMER_COMMUNICATE, boolQueryBuilder, fieldTime, fieldGroup);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, elasticAggsPojo, RedisTimeConstant.TINY_DURATION);
        return elasticAggsPojo;
    }
    /**
     * 成交的跟进客户
     * @param chartResultPojo
     * @return com.xbongbong.pro.statistic.pojo.vo.ResultCountListVO
     * @throws XbbException
     * @author zcp
     * @date 2019/2/25 20:40
     * @since v1.0
     * @version v1.0
     */
    private ResultCountListVO customerFollowOk2ResultCountListVO(ChartResultPojo chartResultPojo) throws XbbException {
        //成交的跟进客户统一用SystemCodeEnum.CUSTOMER_FOLLOW_OK作为缓存唯一标识
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPojo, SystemCodeEnum.CUSTOMER_FOLLOW_OK);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ResultCountListVO resultCountListVO = JsonHelperUtil.parseObject(redisResult, ResultCountListVO.class);
        if (Objects.nonNull(resultCountListVO)) {
            return resultCountListVO;
        }
        /*--------先塞入跟进查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.communicateQuery4UserLimitStart(chartResultPojo);
        String fieldTime = CustomerCommunicateEnum.getEsAttr4Keyword(CustomerCommunicateEnum.COMMUNICATE_TIME);
        //查询字段
        String fieldQuery = CustomerCommunicateEnum.getEsAttr4Keyword(CustomerCommunicateEnum.CUSTOMER_NAME);
        //排重字段---客户id
        String fieldGroup = CustomerCommunicateEnum.getEsAttr4Keyword(CustomerCommunicateEnum.CUSTOMER_NAME);
        /*--------再塞入成交的客户id查询条件--------*/
        FloorAggsKeyPojo okFloorAggsKeyPojo = customerOk2ElasticAggsPojo(chartResultPojo);
        Set okTotalSet = okFloorAggsKeyPojo.getTotalSet();
        Map<String, Set> okRresultMap = okFloorAggsKeyPojo.getResultMap();
        if (okTotalSet.size() == 0) {
            okTotalSet.add(-1);
        }
        boolQueryBuilder.filter(termsQuery(fieldQuery, okTotalSet));
        //移除formId，成交不限制合同的formId
        esHelper.removeSearchCondition(boolQueryBuilder, "formId");

        FloorAggsKeyPojo followFloorAggsKeyPojo = systemChartHelp.getFloorAggsKey(chartResultPojo, IndexTypeEnum.IDX_SAAS_CUSTOMER_COMMUNICATE, boolQueryBuilder, fieldTime, fieldGroup, true);
        Map<String, Set> followRresultMap = followFloorAggsKeyPojo.getResultMap();
        Set followTotalSet = followFloorAggsKeyPojo.getTotalSet();

        List<Integer> resultList = new ArrayList<>();
        for (Entry<String, Set> entry : followRresultMap.entrySet()) {
            Set communicateSet = entry.getValue();
            Set contractSet = okRresultMap.get(entry.getKey());
            if (communicateSet != null && contractSet != null) {
                communicateSet.retainAll(contractSet);
                resultList.add(communicateSet.size());
            } else {
                resultList.add(0);
            }
        }
        resultCountListVO = new ResultCountListVO(followTotalSet.size(), resultList);
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, resultCountListVO, RedisTimeConstant.TINY_DURATION);
        return resultCountListVO;
    }
    /**
     * 格式化所有客户、成交客户其中一种情况没有“未知”，而另一个里面含有“未知”
     * @param list 所有客户结果
     * @param okList 成交客户结果
     * @author zcp
     * @date 2019/2/26 21:31
     * @since v1.0
     * @version v1.0
     */
    private void formatUnknow(List<ResultDataSeriesChartVO> list, List<ResultDataSeriesChartVO> okList){
        int allSize = list.size();
        int okSize = okList.size();
        if (allSize == okSize) {
            return;
        }else if (allSize > okSize) {
            ResultDataSeriesChartVO otherVO = new ResultDataSeriesChartVO("未知[0]个", "未知", "未知", "0");
            okList.add(otherVO);
            return;
        }else if (allSize < okSize) {
            ResultDataSeriesChartVO otherVO = new ResultDataSeriesChartVO("未知[0]个", "未知", "未知", "0");
            list.add(otherVO);
            return;
        }
    }

    /**
     * 按阶段聚合，得到最终各个阶段的客户数
     * @param chartResultPojo 参数pojo
     * @return com.xbongbong.pro.statistic.pojo.vo.StageFunnelVO
     * @author zcp
     * @date 2019/3/8 15:15
     * @since v1.0
     * @version v1.0
     */
    private StageFunnelPojo getFunnel4Customer(ChartResultPojo chartResultPojo) throws XbbException {
        String fieldTime = "addTime";
        //BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Team(chartResultPojo, fieldTime, true);

        //BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4Form(chartResultPojo, fieldTime, true);
        //获取特定的客户阶段（客户formId）
        StageFindStrategy stageFindStrategy = StageFindFactory.getStageFindStrategy(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
        List<? extends PaasStageEntity> saleStageList = stageFindStrategy.findStageListSpecial(chartResultPojo.getCorpid(), new StageFindPojo(chartResultPojo.getRefId(), chartResultPojo.getArgTwoId()));
        List<String> allStageCodeIn = new ArrayList<>();
        //普通阶段code集合，结束阶段（成功、失败、取消）不用计算停留时长
        List<String> ordinaryCodeIn = new ArrayList<>();
        List<Integer> ordinaryTypeList = StageTypeEnum.getOrdinaryType();
        for (PaasStageEntity stage : saleStageList) {
            String code = stage.getCode();
            Integer type = stage.getType();
            allStageCodeIn.add(code);
            if (ordinaryTypeList.contains(type)) {
                ordinaryCodeIn.add(code);
            }
        }
        /*--------处理查询条件--------*/
        Long formId = chartResultPojo.getRefId();
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4Base(chartResultPojo.getCorpid());
        if (formId != null && formId > 0) {
            boolQueryBuilder.filter(termQuery("formId", formId));
        }

        //无需审批和通过
        boolQueryBuilder.filter(termsQuery("flowStatus", FlowStatusEnum.getStatisticType()));
        chartQueryHelp.customerFunnelQuery(chartResultPojo, boolQueryBuilder, true, null);

        //---------------按阶段
        String field = CustomerManagementEnum.getEsAttr4Keyword(CustomerManagementEnum.CUSTOMER_STAGE);
        boolQueryBuilder.filter(termsQuery(field, allStageCodeIn));
        //一层聚合：按照阶段id聚合分组一层即可
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field(field);
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        termsAggregationBuilder.size(Integer.MAX_VALUE);
        //在上面的customerFunnelQuery方法中： 当前公司以updateTime维度统计时，会额外拼接客户id，当前请求体数据大小超过1m（es默认配置）的话，es会直接拒绝访问，因此这里做了限制
        int length = boolQueryBuilder.toString().getBytes(StandardCharsets.UTF_8).length;
        JSONObject resultJsonObject;
        if(length > SizeConstant.ES_REQUEST_DATA_LIMIT){
            LOG.warn("es请求体超过最大限制, corpid： " + chartResultPojo.getCorpid() + " 当前请求体长度： " + length);
            resultJsonObject = new JSONObject();
            resultJsonObject.put("buckets",new JSONArray());
        }else{
            IndexTypeEnum customerIndex = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
            resultJsonObject = esHelper.elasticAggs4Buckets2Object(customerIndex, boolQueryBuilder, termsAggregationBuilder);
        }
        JSONArray bucketsArray = resultJsonObject.getJSONArray("buckets");
        /**
         * 阶段id--该阶段对应的客户数
         */
        Map<String, StageFunnelInfoPojo> stageIdInfoMap = new HashMap<>(bucketsArray.size());
        //总数
        int total = 0;
        for (Object object : bucketsArray) {
            if(object!=null){
                JSONObject json = (JSONObject) object;
                String code = json.getString("key");
                Integer count = json.getInteger("doc_count");
                total += count;
                StageFunnelInfoPojo stageFunnelInfoPojo = new StageFunnelInfoPojo(count);
                stageIdInfoMap.put(code, stageFunnelInfoPojo);
            }
        }
        //只把非结束阶段的code放入集合
        StageFunnelPojo stageFunnelPojo = new StageFunnelPojo(total, stageIdInfoMap, saleStageList, ordinaryCodeIn);
        return stageFunnelPojo;
    }
    /**
     * 封装漏斗报表中心客户漏斗所需数据
     * 包含：阶段转化率、平均停留时长等
     * @param chartResultPojo 请求系统指标接口需要用到的pojo类（内部存系统指标统计时需要的参数）
     * @param chartResultDetailVO 统计需要渲染的图（表---可能同时存在，可能某一个存在）塞入该vo
     * @param saleStageList 阶段list
     * @param stageFunnelPojo 漏斗vo，封装各个阶段的信息
     * @param dayMap 阶段code--平均停留时长
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultDetailVO
     * @author zcp
     * @date 2019/3/11 16:05
     * @since v1.0
     * @version v1.0
     */
    private ChartResultDetailVO packageFunnelFull(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO, List<? extends PaasStageEntity> saleStageList, StageFunnelPojo stageFunnelPojo, Map<String, Double> dayMap){
        //阶段id--该阶段对应的数量
        Map<String, StageFunnelInfoPojo> stageIdInfoMap = stageFunnelPojo.getStageIdInfoMap();
        //声明图和表的信息VO
        List<ResultChartVO> resultChartVOList = new ArrayList<>();
        ResultChartVO resultChartVO = new ResultChartVO();
        List<ResultDataSeriesChartVO> dataSeriesList = new ArrayList<>();
        ResultTableVO resultTableVO = new ResultTableVO();
        List<String> title = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.CUSTOMER_STAGE_TITLE).split(","));
        resultTableVO.setTitle(systemChartHelp.titleNumRight(title));
        List<List<ResultDataTableVO>> resultDataTableVOList = new ArrayList<>();
        ChartEntity chartEntity = chartResultPojo.getChartEntity();
        if (chartEntity != null) {
            BeanUtil.copyProperties(chartEntity, resultChartVO);
        }
        boolean isRunOffButtonStart = true;
        boolean isRunOff;
        int size = saleStageList.size();
        int average = (size == 0) ? 0 : 100 / size;
        int flagValue = 0;
        //该阶段后面所有阶段的总数（除去该阶段）
        int nextCount = stageFunnelPojo.getTotal();
        JSONArray buttonJsonArray = chartEntity.getButtonAttr();
        if (Objects.isNull(buttonJsonArray)){
            buttonJsonArray = new JSONArray();
        }
        if (CollectionUtils.isNotEmpty(buttonJsonArray)) {
            for (int i = 0; i < buttonJsonArray.size(); i++) {
                JSONObject jsonObject = buttonJsonArray.getJSONObject(i);
                String config = jsonObject.getString("config");
                String enable = jsonObject.getString("configValue");
                ChartConfigEnum chartConfigEnum = ChartConfigEnum.getByConfig(config);
                switch (chartConfigEnum) {
                    case FUNNEL_CUSTOMER_RUN_OFF_BUTTON:
                        isRunOffButtonStart = Objects.equals(enable, StringConstant.POSITIVE_NUMBER);
                        break;
                    default:
                        break;
                }
            }
        }
        //处理穿透
        ThroughDTO throughDto = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPojo.getFiscalYearTimePojo(), chartResultPojo.getStartTime(), chartResultPojo.getEndTime());
        for (int i = 0; i < size; i++) {
            PaasStageEntity saleStageEntity = saleStageList.get(i);
            String realName = saleStageEntity.getName();
            String code = saleStageEntity.getCode();
            isRunOff = Objects.equals(StageTypeEnum.FAIL_STAGE.getType(), saleStageEntity.getType());
            if (  !isRunOffButtonStart && isRunOff )  {
                continue;
            }
            StageFunnelInfoPojo stageFunnelInfoPojo = stageIdInfoMap.get(code);
            int count = (stageFunnelInfoPojo == null)? 0: stageFunnelInfoPojo.getCount();
            /**
             处理阶段转化率（最后一个赢单阶段无需计算），以及阶段停留时长：除了该阶段以及该阶段前面的数，即该阶段后面所有阶段的总数
             最后一个赢单阶段无需计算转化率和停留时长
             */
            nextCount -= count;
            String name = realName;
            String changeRateStr = "-";
            String averageDayStr = "-";
            //普通阶段才有停留时长
            if (stageFunnelPojo.getCalcStayStageCodeIn().contains(code)) {
                changeRateStr = "0%";
                //当前阶段以及该阶段后面的所有总数
                int nowAndNextAllCount = nextCount + count;
                if (nowAndNextAllCount > 0) {
                    // 转化率（转化到下一阶段的成功率） = 该阶段后面所有阶段机会总数（乘以100，前端显示直接拼“%”即可）/ 当前时间段内所有机会作为该阶段的转化率
                    changeRateStr = Arith.div(nextCount * 100d, nowAndNextAllCount, 2) + "%";
                }
                Double day = dayMap.get(code);
                averageDayStr = day == null ? "-" : String.valueOf(day);
                name += String.format(I18nMessageUtil.getMessage(ChartI18Constant.CLUE_STAGE_CONTENT_1), count, averageDayStr);
            } else {
                name += String.format(I18nMessageUtil.getMessage(ChartI18Constant.CLUE_STAGE_CONTENT_2), count);
            }
            int value;
            if (i == 0) {
                value = 100;
            } else if (i < size) {
                value = 100 - average * i;
            } else {
                value = 100 - flagValue;
            }
            flagValue = value;
            //置入穿透需要的阶段code
            throughDto.setDictionaryCodeThrough(code);
            String through = throughHelp.getThrough(throughDto, timePojo);
            ResultDataSeriesChartVO dataSeries = new ResultDataSeriesChartVO(name, realName, code, String.valueOf(value));
            dataSeries.setThrough(through);
            dataSeriesList.add(dataSeries);
            ResultDataTableVO nameVo = new ResultDataTableVO(realName, null);
            ResultDataTableVO countVo = new ResultDataTableVO(String.valueOf(count), through);
            ResultDataTableVO changeRateVo = new ResultDataTableVO(changeRateStr, null);
            ResultDataTableVO averageDayVo = new ResultDataTableVO(averageDayStr, null);
            List<ResultDataTableVO> resultDataTableVOs = Arrays.asList(nameVo, countVo, changeRateVo, averageDayVo);
            resultDataTableVOList.add(resultDataTableVOs);
        }
        resultChartVO.setDataSeries(dataSeriesList);
        resultChartVOList.add(resultChartVO);
        resultTableVO.setData(resultDataTableVOList);
        resultTableVO.setTableName("客户阶段漏斗");
        chartResultDetailVO.setChart(resultChartVOList);
        chartResultDetailVO.setTable(resultTableVO);
        return chartResultDetailVO;
    }
    /**
     * 平均停留时长
     * 分两种情况：
     * （1）还处于该阶段，则按照截至到nowTime（当前时间）减去进入该阶段的时间，差值即停留时长；
     * （2）已经改到下面的阶段，则直接按照离开阶段的时间减去进入到该阶段时的时间，差值即停留时长。
     * @param chartResultPojo 参数pojo
     * @param saleStageIdIn 要查询的阶段ids
     * @return java.util.Map<java.lang.String,java.lang.Double>
     * @throws XbbException
     * @author zcp
     * @date 2019/3/10 16:25
     * @since v1.0
     * @version v1.0
     */
    private Map<String, Double> getAverageStayTime(ChartResultPojo chartResultPojo, List<String> saleStageIdIn) throws XbbException {
        String fieldTime = "addTime";
        //BoolQueryBuilder boolQueryBuilder = chartQueryHelp.customerQuery4Team(chartResultPojo, fieldTime, true);

        //BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4Form(chartResultPojo, fieldTime, true);
        /*--------处理查询条件--------*/
        Long formId = chartResultPojo.getRefId();
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4Base(chartResultPojo.getCorpid());
        if (formId != null && formId > 0) {
            boolQueryBuilder.filter(termQuery("formId", formId));
        }

        //无需审批和通过
        boolQueryBuilder.filter(termsQuery("flowStatus", FlowStatusEnum.getStatisticType()));
        chartQueryHelp.customerFunnelQuery(chartResultPojo, boolQueryBuilder, true, null);
        //数据量超限（SizeConstant.BI_MUITI_DATA_LIMIT），不处理
        IndexTypeEnum indexTypeEnum = indexTypeModel.getCustomerIndex(chartResultPojo.getCorpid(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
        long count = paasEsModel.count(boolQueryBuilder, indexTypeEnum);
        if(count > SizeConstant.BI_MUITI_DATA_LIMIT){
            return new HashMap<>(BasicConstant.ONE);
        }
        List<String> fieldList = Arrays.asList(FieldTypeEnum.DATAID.getAlias());

        List<PaasFormDataEntityExt> list = esHelper.findByScroll(indexTypeEnum, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList);
        Set<Long> customerIdSet = new HashSet<>();
        for (PaasFormDataEntityExt entityExt: list){
            customerIdSet.add(entityExt.getDataId());
        }
        return customerStageLogModel.getAverageStayTime(chartResultPojo.getCorpid(), customerIdSet, saleStageIdIn);
    }
}
